关于javascript:将复杂元素添加到页面时,事件委托与直接绑定

Event delegation vs direct binding when adding complex elements to a page

我有一些这样的标记(类只是为了说明):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<li>

    <header class="show-after-collapse">Top-Line Info</header>
    <section class="hide-after-collapse">
     
       
<li>

          <header class="show-after-collapse">Top-Line Info</header>
          <section class="hide-after-collapse">
            Content A
          </section>
       
</li>

     
    </section>
 
</li>

 
<li>

    <header/>
    <section class="hide-after-collapse">
     
       
<li>

          <header/>
          <section class="hide-after-collapse">
            Content B
          </section>
       
</li>

     
    </section>
 
</li>

即嵌套的可排序列表。可排序的插件就足够了,因为尽管内部列表已连接,但每个li(以下称" item")都保持其级别。这些项目具有始终可见的标题和在展开状态下可见的部分,可通过单击标题进行切换。用户可以随意从任一级别添加和删除项目。添加顶级商品将在其中包含一个空的嵌套列表。我的问题是关于新创建项目的JS初始化:尽管它们将共享一些通用功能,但我可以通过

进行介绍

1
2
3
$("#root").on("click","li > header", function() {
  $(this).parent().toggleClass("collapsed");
});

1
2
3
li.collapsed section {
  display: none;
}

(旁问:这是使用details / summary HTML5标签的合适地方吗?对于这些标签是否甚至可以将其纳入最终规范似乎有些不确定,我想进行一次滑动过渡,所以看起来无论如何,我都需要JS。但是我把这个问题扔给了大众。你好,大众。)

如果根列表是保证页面加载时存在的唯一(相关)元素,为了使.on()有效运行,我必须将所有事件绑定到该元素,并为每个元素拼出精确的选择器据我了解。因此,例如,要将单独的功能绑定到彼此相邻的两个按钮上,我每次都必须完整拼写选择器,


使用$(<root-element>).on(<event>, <selector>)绑定事件将减少CPU开销,因为将绑定到单个" root "元素,而不是可能绑定更多的单个后代元素(每个绑定都需要时间...)。铅>

也就是说,当实际事件发生时,您将招致更多的CPU开销,因为它们必须使DOM膨胀到" root "元素。

短篇小说:绑定事件处理程序时,委托可以节省CPU;当事件触发时(例如用户单击某物),bind可以节省CPU。

由您决定哪个点对性能更重要。添加新元素时,您是否有可用的CPU?如果是这样,则直接绑定到新元素将是整体性能最佳的选择,但是如果添加元素是占用大量CPU的操作,则您可能需要委派事件绑定,并让事件触发从所有冒泡事件中产生一些额外的CPU开销。

请注意:

1
$(<root-element>).on(<event>, <selector>, <event-handler>)

与:

相同

1
$(<root-element>).delegate(<selector>, <event>, <event-handler>)

那:

1
$(<selector>).on(<event>, <event-handler>)

与:

相同

1
$(<selector>).bind(<event>, <event-handler>)

.on()是jQuery 1.7中的新增功能,如果使用1.7,则.delegate(<selector>, <event>, <event-handler>)只是.on(<event>, <selector>, <event-handler>)的快捷方式。

更新

此处是一项性能测试,表明委派事件绑定比单独绑定每个元素要快:http://jsperf.com/bind-vs-click/29。不幸的是,这性能测试已删除。

更新

此处是一项性能测试,显示当您直接绑定到元素而不是委派绑定时,事件触发会更快:http://jsperf.com/jquery-delegate-vs-bind-triggering(请注意,这不是\\' ta完美的性能测试,因为绑定方法包含在测试中,但是由于delegate在绑定时运行得更快,这仅意味着bind在谈论触发时甚至相对更快。


由于接受的答案具有不正确的测试(顺便说一句:测试您的代码,衡量性能,不要只是盲目地遵循一些"规则",这不是优化的方法!),这是错误的,我已修复测试:
https://jsperf.com/jquery-delegate-vs-bind-triggering/49

证明在这样简单的示例中,委托或直接绑定之间没有区别

委派总是很糟糕的唯一情况是鼠标移动和滚动之类的事件-每秒触发x次。在这里,您会发现任何性能差异。

如果您在单个事件上(例如单击)甚至相差1毫秒(不会发生,但这只是一个例子),您将不会注意到这一点。如果您在一秒钟内发生100次事件的时间差为1毫秒-您会注意到CPU消耗。

仅拥有数千个元素不会对委派的性能产生负面影响-实际上-应该使用它们的情况-避免在附加数千个事件处理程序时占用CPU。

因此,如果您确实需要遵循规则(不要这样做),请对除鼠标移动,滚动和其他可能会持续触发的其他事件以外的所有事物使用委派。