是应该将所有jquery事件绑定到$(文档)?

Buc*_*uck 157 javascript jquery jquery-selectors jquery-on

这是来自哪里

当我第一次学习jQuery时,我通常会附加这样的事件:

$('.my-widget a').click(function() {
    $(this).toggleClass('active');
});
Run Code Online (Sandbox Code Playgroud)

在了解了有关选择器速度和事件委托的更多信息之后,我在几个地方读到"jQuery事件委托将使您的代码更快".所以我开始编写这样的代码:

$('.my-widget').on('click','a',function() {
    $(this).toggleClass('active');
});
Run Code Online (Sandbox Code Playgroud)

这也是复制已弃用的.live()事件行为的推荐方法.这对我很重要,因为我的很多网站都在动态添加/删除小部件.上面的行为与.live()的行为完全不同,因为只有添加到现有容器".my-widget"的元素才会获得行为.如果我在代码运行后动态添加另一个html块,那么这些元素将不会获取绑定到它们的事件.像这样:

setTimeout(function() {
    $('body').append('<div class="my-widget"><a>Click does nothing</a></div>');
}, 1000);
Run Code Online (Sandbox Code Playgroud)


我想要实现的目标:

  1. .live()的旧行为//意味着将事件附加到尚未存在的元素
  2. .on()的好处
  3. 绑定事件的最快性能
  4. 管理事件的简单方法

我现在附上所有这样的事件:

$(document).on('click.my-widget-namespace', '.my-widget a', function() {
    $(this).toggleClass('active');
});
Run Code Online (Sandbox Code Playgroud)

这似乎符合我的所有目标.(是的,因为某种原因它在IE中速度较慢,不知道为什么?)它很快,因为只有一个事件与单个元素相关联,而二级选择器仅在事件发生时进行评估(如果这里错误,请纠正我).命名空间非常棒,因为它可以更容易地切换事件监听器.

我的解决方案/问题

所以我开始认为jQuery事件应该始终绑定到$(document).
你有什么理由不想这样做吗?
这可算是最佳做法吗?如果没有,为什么?

如果您已经阅读了这一切,谢谢.我感谢任何/所有反馈/见解.

假设:

  1. 使用支持.on()//至少1.7版的jQuery
  2. 您希望将事件添加到动态添加的内容中

读数/例子:

  1. http://24ways.org/2011/your-jquery-now-with-less-suck
  2. http://brandonaaron.net/blog/2010/03/4/event-delegation-with-jquery
  3. http://www.jasonbuckboyer.com/playground/speed/speed.html
  4. http://api.jquery.com/on/

jfr*_*d00 208

否 - 您不应该将所有委派的事件处理程序绑定到该document对象.这可能是您可以创建的表现最差的场景.

首先,事件委托并不总能使您的代码更快.在某些情况下,它是有利的,在某些情况下不是.当您真正需要事件委派时以及从中受益时,您应该使用事件委派.否则,您应该将事件处理程序直接绑定到事件发生的对象,因为这通常会更有效.

其次,您不应该在文档级别绑定所有委派的事件.这正是为什么.live()被弃用的原因,因为当你以这种方式绑定大量事件时,效率非常低.对于委托事件处理,将它们绑定到非动态的最近父节点会更有效.

第三,并非所有事件都有效,或者所有问题都可以通过授权来解决.例如,如果要拦截输入控件上的键事件并阻止将无效键输入到输入控件中,则无法通过委派事件处理来执行此操作,因为当事件冒泡到委派处理程序时,它已经由输入控件处理,影响该行为为时已晚.

以下是需要或有利的事件委托时间:

  • 当您捕获事件的对象被动态创建/删除时,您仍然希望捕获它们上的事件,而无需在每次创建新事件时显式重新绑定事件处理程序.
  • 当你有很多对象都需要完全相同的事件处理程序(其中批量至少为数百).在这种情况下,在设置时绑定一个委托事件处理程序而不是数百个或更多直接事件处理程序可能更有效.请注意,委派事件处理在运行时的效率始终低于直接事件处理程序.
  • 当您尝试捕获(在文档中的更高级别)文档中任何元素上发生的事件时.
  • 当您的设计明确使用事件冒泡和stopPropagation()来解决页面中的某些问题或功能时.

要了解这一点,需要了解jQuery如何委托事件处理程序工作.当你打这样的话:

$("#myParent").on('click', 'button.actionButton', myFn);
Run Code Online (Sandbox Code Playgroud)

它在#myParent对象上安装通用的jQuery事件处理程序.当click事件冒泡到此委托事件处理程序时,jQuery必须遍历附加到此对象的委托事件处理程序列表,并查看该事件的原始元素是否与委派事件处理程序中的任何选择器匹配.

因为选择器可以公平地参与,这意味着jQuery必须解析每个选择器,然后将其与原始事件目标的特征进行比较,以查看它是否与每个选择器匹配.这不是一个便宜的操作.如果只有其中一个,这没什么大不了的,但是如果你把所有选择器放在文档对象上并且有数百个选择器可以与每个冒泡事件进行比较,那么这可能会严重影响事件处理性能.

因此,您需要设置委派的事件处理程序,以便委托事件处理程序尽可能接近目标对象.这意味着每个委托事件处理程序中的事件将会减少,从而提高性能.将所有委派事件放在文档对象上是最糟糕的性能,因为所有冒泡事件都必须通过所有委托事件处理程序并针对所有可能的委托事件选择器进行评估.这正是为什么.live()被弃用的原因,因为这是做了什么.live(),并且它被证明是非常低效的.


因此,要实现优化的性能:

  1. 仅在实际提供所需功能或提高性能时才使用委派事件处理.不要总是使用它,因为它很容易,因为当你实际上不需要它时.它实际上在事件发送时比直接事件绑定表现更差.
  2. 将委派的事件处理程序附加到事件源的最近父级.如果您正在使用委派事件处理,因为您具有要为其捕获事件的动态元素,则选择最靠近其自身不动态的父级.
  3. 为委派的事件处理程序使用易于评估的选择器.如果您遵循委托事件处理的工作原理,您将理解委托事件处理程序必须多次与大量对象进行比较,以便尽可能高效地选择选择器或向对象添加简单类,以便可以使用更简单的选择器提高委派事件处理的性能.

  • @ user1394692 - 如果你有很多几乎相同的元素,那么为它们使用委托事件处理程序可能是有意义的.我在答案中说.如果我有一个巨大的500行表并且在特定列的每一行中都有相同的按钮,我会在表上使用一个委托事件处理程序来为所有按钮提供服务.但是如果我有200个元素并且它们都需要自己独特的事件处理程序,那么安装200个委托事件处理程序并不比安装200个直接绑定事件处理程序更快,但是在事件执行时委托事件处理可能会慢得多. (5认同)
  • 真棒.感谢您快速详细的描述.通过使用.on()可以增加事件发送时间,但我认为我仍然在努力决定增加的事件发送时间与初始页面处理团队之间的关系.我通常会减少初始页面时间.例如,如果我在一个页面上有200个元素(并且事件发生的时间更多),那么在初始加载时它的成本大约高出100倍(因为它必须添加100个事件侦听器)而不是在我添加单个事件侦听器时父容器[link](http://jsperf.com/jquery-event-delegation) (2认同)

Sel*_*gam 8

事件委托是一种在元素实际存在于DOM之前编写处理程序的技术.此方法有其自身的缺点,只有在您有此类要求时才应使用.

什么时候应该使用事件委托?

  1. 为更多需要相同功能的元素绑定公共处理程序时.(例如:表格行悬停)
    • 在该示例中,如果必须使用直接绑定绑定所有行,则最终将为该表中的n行创建n处理程序.通过使用委托方法,您最终可以在一个简单的处理程序中处理所有这些.
  2. 在DOM中更频繁地添加动态内容时(例如:从表中添加/删除行)

为什么不应该使用事件委托?

  1. 与将事件直接绑定到元素相比,事件委托更慢.
    • 它将目标选择器与它所击中的每个气泡进行比较,这种比较既复杂又昂贵.
  2. 无法控制事件冒泡,直到它碰到它所绑定的元素.

PS:即使是动态内容,如果在内容插入DOM后绑定处理程序,也不必使用事件委托方法.(如果添加动态内容不经常删除/重新添加)