te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - Best practices for where to add event listeners - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Best practices for where to add event listeners - Stack Overflow

programmeradmin4浏览0评论

On my page, the user clicks on an element in order to edit it. To facilitate this, I assign the class editable to all such elements.

How should I listen for clicks on all these elements? Currently, I'm doing this:

document.body.addEventListener("click", (event) => {
  if (event.target.classList.contains("editable")) {
    // do stuff
  }
});

The alternative would be to set a listener on every element, like this:

const editables = document.getElementsByClassName("editable");
for (const editable of editables) {
    editable.addEventListener("click", editElement);
}

It seems to me that the first way must be better for performance, since it's only one element being listened on, but is it possible to degrade performance by attaching all such events to the body element? Are there any other considerations (e.g. browser implementations of event handling) that I'm neglecting which would suggest doing it the second way?

On my page, the user clicks on an element in order to edit it. To facilitate this, I assign the class editable to all such elements.

How should I listen for clicks on all these elements? Currently, I'm doing this:

document.body.addEventListener("click", (event) => {
  if (event.target.classList.contains("editable")) {
    // do stuff
  }
});

The alternative would be to set a listener on every element, like this:

const editables = document.getElementsByClassName("editable");
for (const editable of editables) {
    editable.addEventListener("click", editElement);
}

It seems to me that the first way must be better for performance, since it's only one element being listened on, but is it possible to degrade performance by attaching all such events to the body element? Are there any other considerations (e.g. browser implementations of event handling) that I'm neglecting which would suggest doing it the second way?

Share Improve this question edited Sep 14, 2021 at 0:04 Chris Middleton asked Sep 29, 2014 at 16:26 Chris MiddletonChris Middleton 5,9425 gold badges37 silver badges70 bronze badges 1
  • 1 Notice that your first snippet doesn't catch any clicks on child elements of your editables, while the second snippet does. – Bergi Commented Sep 29, 2014 at 16:32
Add a ment  | 

2 Answers 2

Reset to default 12

Short answer: definitely do it the first way. Event delegation is way more performant, but requires extra conditionals in your code, so it's basically a plexity versus performance tradeoff.

Longer Answer: For a small number of elements, adding individual event handlers works fine. However, as you add more and more event handlers, the browser's performance begins to degrade. The reason is that listening for events is memory intensive.

However, in the DOM, events "bubble up" from the most specific target to the most general triggering any event handlers along the way. Here's an example:

<html>
    <body>
        <div>
            <a>
                <img>
            </a>
         </div>
    </body>
</html>

If you clicked on the <img> tag, that click event would fire any event handlers in this order:

  1. img
  2. a
  3. div
  4. body
  5. html
  6. document object

Event delegation is the technique of listening to a parent (say <div>) for a bunch of event handlers instead of the specific element you care about (say <img>). The event object will have a target property which points to the specific dom element from which the event originated (in this case <img>).

Your code for event delegation might look something like this:

$(document).ready(function(){
    $('<div>').on('click', function(e) {
        // check if e.target is an img tag
        // do whatever in response to the image being clicked
    });
});

For more information checkout Dave Walsh's blog post on Event Delegation or duckduckgo "event delegation".

NOTE ON CODE SAMPLE IN OP: In the first example, target.hasClass('editable') means that the specific thing clicked on must have the class editable for the if block to execute. As one of the menters pointed out, that's probably not what you want. You might want to try something along these lines instead:

$(document).on('click', function(e) {
   if ($(e.target).parents(".editable").length) {
       // Do whatever
   }
});

Let's break that down a bit:

  • $(e.target) - anything that on the page that was clicked converted to jQuery
  • .parents(".editable") - find all the ancestors of the element clicked, then filter to only include ones with the class "editable"
  • .length - this should be an integer. If 0, this means there are no parents with "editable" class

Another plus point for the first method

I was using the second (alternative) method that you have mentioned I noticed that when the ajax loaded... the newly created elements were not listening the event. I had to redo the for loop after ajax every time.

With the first method which looks like following in my code also works with ajax.

document.addEventListener('click', function (e) {
    if (hasClass(e.target, 'classname')) { 
        // do stuff
    } 
}, false);

So first one is better

发布评论

评论列表(0)

  1. 暂无评论