应该所有的jQuery事件绑定到$(文档)?

这是从哪里来的

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

$('.my-widget a').click(function() { $(this).toggleClass('active'); }); 

在了解了关于select器速度和事件委托的更多信息之后,我在几处地方读到“jQuery事件委托会让你的代码更快”。 所以我开始写这样的代码:

 $('.my-widget').on('click','a',function() { $(this).toggleClass('active'); }); 

这也是复制已弃用的.live()事件行为的推荐方法。 这对我来说很重要,因为我的许多站点都会dynamic地添加/删除小部件。 上面的行为不像.live()虽然,因为只有添加到已经存在的容器“.my-widget”元素将得到的行为。 如果我在代码运行之后dynamic添加另一个html块,那些元素将不会获取绑定到它们的事件。 喜欢这个:

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

我想实现的是:

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

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

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

这似乎满足我所有的目标。 (是的,因为某些原因,在IE中速度较慢,不知道为什么?)这样做很快,因为只有一个事件绑定到一个单数元素,次级select器只在事件发生时才被评估(如果这里错了,请纠正我)。 命名空间非常棒,因为它更容易切换事件侦听器。

我的解决scheme/问题

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

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

假设:

  1. 使用支持.on() //至less1.7版本的jQuery
  2. 您希望将事件添加到dynamic添加的内容

读数/例子:

  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/

否 – 您不应将所有委派的事件处理程序绑定到document对象。 这可能是您可以创build的performance最差的场景。

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

其次,您不应该在文档级绑定所有委托事件。 这就是为什么.live()被弃用的原因,因为当你有很多这样绑定的事件时,这是非常低效的。 对于委托事件处理,将它们绑定到最近的不是dynamic的父对象上会更有效率。

第三,不是所有的事情都可以工作,或者所有的问题都可以通过授权来解 例如,如果要截取input控件上的键事件,并阻止无效键input到input控件中,则不能使用委托事件处理来完成此操作,因为当事件冒泡到委托处理程序时,它已经已经被input控制处理,并且影响该行为为时已晚。

以下是需要或有利事件代表团的时间:

  • 当捕获事件的对象被dynamic创build/移除时,您仍然希望捕获事件,而不必在每次创build新事件时都明确重新绑定事件处理程序。
  • 当你有很多的对象都想要完全相同的事件处理程序(其中地段至less有数百个)。 在这种情况下,在设置时绑定一个委托事件处理程序而不是数百个或更多的直接事件处理程序可能会更有效。 请注意,委托事件处理在运行时总是比直接事件处理程序效率低。
  • 当您尝试捕获文档中任何元素上发生的事件(在文档的更高级别)时。
  • 当您的devise明确使用事件冒泡和stopPropagation()来解决您的页面中的一些问题或function。

为了理解这一点,需要了解jQuery委托事件处理程序是如何工作的。 当你调用这样的东西时:

 $("#myParent").on('click', 'button.actionButton', myFn); 

它在#myParent对象上安装一个通用的jQuery事件处理程序。 当点击事件冒泡到这个委托的事件处理程序时,jQuery必须通过附加到该对象的委托事件处理程序的列表,并查看该事件的原始元素是否与委托事件处理程序中的任何select器匹配。

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

出于这个原因,你想设置你的委托事件处理程序,所以委托事件处理程序尽可能接近目标对象。 这意味着更less的事件将通过每个委托的事件处理程序冒泡,从而提高性能。 将所有委托事件放在文档对象上是最差的performance,因为所有冒泡的事件都必须经过所有的委托事件处理程序,并针对所有可能的委托事件select器进行评估。 这正是为什么.live()被弃用的原因,因为这是.live()所做的事情,而且它被certificate是非常低效的。


所以,要实现优化的性能:

  1. 只有在实际提供您需要的function或提高性能时才使用委派的事件处理。 不要总是使用它,因为它很容易,因为当你不需要它。 事件调度时间实际上比直接事件绑定更糟糕。
  2. 尽可能将委派的事件处理程序附加到最近的父事件源。 如果您正在使用委托事件处理,因为您有要捕获事件的dynamic元素,请select不是自身dynamic的最接近的父元素。
  3. 为委派的事件处理程序使用易于评估的select器。 如果你遵循委托事件处理的工作方式,你将会明白委托的事件处理器必须与许多对象进行比较,以便尽可能有效地select一个select器或向对象添加简单的类,这样可以使用更简单的select器提高委托事件处理的性能。

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

什么时候应该使用事件代表团?

  1. 当你为需要相同function的更多元素绑定一个通用处理程序时。 (例如:表格hover)
    • 在这个例子中,如果必须使用直接绑定来绑定所有行,那么最终会在该表中为n行创buildn个处理程序。 通过使用委托方法,您最终可以在一个简单的处理程序中处理所有这些。
  2. 在DOM中更频繁地添加dynamic内容(例如:从表中添加/删除行)

为什么你不应该使用事件代表团?

  1. 与将事件直接绑定到元素相比,事件委托速度较慢。
    • 它比较目标select器在每一个碰到的泡泡上,比较起来就像是复杂的那样昂贵。
  2. 无法控制事件冒泡,直到它遇到绑定的元素。

PS:即使对于dynamic内容,如果在内容插入到DOM之后绑定处理程序,则不必使用事件委托方法。 (如果dynamic内容被添加不经常移除/重新添加)