添加事件侦听器的最佳做法

时间:2014-09-29 16:26:35

标签: javascript event-handling event-bubbling

在我的页面上,用户点击某个元素以进行编辑。为了实现这一点,我将课程editable分配给所有这些元素。

我应该如何听取所有这些元素的点击?目前,我正在这样做:

$lib.addEventListener(document.body, "click", function(event) {
  if($lib.hasClass(event.target, "editable") {
    // do stuff
  }
});

其中$lib是我使用的一个小JS库。

另一种方法是在每个元素上设置一个监听器,如下所示:

var editables = document.getElementsByClassName("editable");
for(var i = 0; i < editables.length; i++) {
    $lib.addEventListener(editables[i], "click", editElement);
}

在我看来,第一种方式必须更好才能提高性能,因为它只是一个被监听的元素,但是可以通过将所有这些事件附加到body元素来降低性能吗?有没有其他考虑因素(例如事件处理的浏览器实现)我忽略哪些会建议以第二种方式进行?

1 个答案:

答案 0 :(得分:6)

简答:绝对是第一种方式。事件委托更具性能,但在代码中需要额外的条件,因此它基本上是复杂性与性能权衡。

更长的答案:对于少量元素,添加单个事件处理程序可以正常工作。但是,随着您添加越来越多的事件处理程序,浏览器的性能开始下降。原因是监听事件是内存密集型的。

然而,在DOM中,事件从最具体的目标“冒泡”到最常见的触发任何事件处理程序。这是一个例子:

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

如果您点击<img>标记,该点击事件将按此顺序触发任何事件处理程序:

  1. IMG
  2. 一个
  3. DIV
  4. HTML
  5. document object
  6. 事件委派是一种监听父级(比如<div>)的技巧,而不是您关注的特定元素(比如<img>) 。事件对象将具有一个target属性,该属性指向事件源自的特定dom元素(在本例中为<img>)。

    您的事件委派代码可能如下所示:

    $(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
        });
    });
    

    有关详情,请查看Dave Walsh的blog post on Event Delegation或duckduckgo“活动代表团”。

    关于OP中代码示例的注释:在第一个示例中,target.hasClass('editable')表示单击的特定内容必须具有可编辑的类才能执行if块。正如其中一位评论者指出的那样,这可能不是你想要的。你可能想尝试沿着这些方向尝试:

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

    让我们稍微打破一下:

    • $(e.target) - 点击页面上转换为jQuery的任何内容
    • .parents(".editable") - 找到点击元素的所有祖先,然后过滤为只包含“可编辑”类的元素
    • .length - 这应该是一个整数。如果为0,则表示没有父母具有“可编辑”类