直接与委派-jQuery .on()


159

我试图理解使用jQuery .on()方法直接事件处理程序和委托事件处理程序之间的特殊区别。具体来说,本段的最后一句话:

selector被提供时,事件处理程序被称为委托。当事件直接发生在绑定元素上时,不调用处理程序,而仅对与选择器匹配的后代(内部元素)进行调用。jQuery使事件从事件目标一直冒泡到附加了处理程序的元素(即,最内层元素到最外层元素),并沿该路径运行与选择器匹配的任何元素的处理程序。

“为任何元素运行处理程序”是什么意思?我做了一个测试页面来试验这个概念。但是以下两个构造导致相同的行为:

$("div#target span.green").on("click", function() {
   alert($(this).attr("class") + " is clicked");
});

要么,

$("div#target").on("click", "span.green", function() {
   alert($(this).attr("class") + " is clicked");
});

也许有人可以参考其他示例来阐明这一点?谢谢。



1
@KevinWheeler我在下面对您的小提琴发表了评论,但在这里,基本上它的设置不正确(您绑定到父元素,并且委派给了孩子)。要回答您的问题,这意味着委派处理程序将匹配新添加的元素,而没有委派的元素将不匹配。委派的好处是,更少的事件挂在浏览器中,从而降低了应用程序的内存消耗,但是要权衡的是它增加了(至少)处理单击的时间。如果您要制作游戏,请不要委派。
vipero07年7

1
您引用的“测试页”无效。
Jaime Montoya

Answers:


372

情况1(直接):

$("div#target span.green").on("click", function() {...});

==嘿!我希望div#target中的每个span.green都可以监听:单击时,请执行X。

案例2(授权):

$("div#target").on("click", "span.green", function() {...});

==嗨,div#target!当您的“ span.green”子元素中的任何一个被单击时,对它们进行X。

换一种说法...

在情况1中,已分别给每个跨度指示。如果创建了新的跨度,他们将不会听到说明,也不会响应点击。每个跨度直接负责其自身的事件。

在情况2中,仅向容器提供了指令;它负责代表其子元素注意到点击。捕获事件的工作已委派。这也意味着该指令将针对将来创建的子元素执行。


45
这是一个很好的解释,为我长期以来一直不理解的问题带来了清晰度。谢谢!
dgo

3
那么,为什么要on()允许两个参数与使用时几乎相同click()呢?
日本,2013年

5
.on()是通用API,可以处理任何类型的事件,包括多个不同的事件(您可以在第一个字符串中放入多个事件名称。).click()只是该第一种形式的简写形式。
N3dst4

1
@ newbie,@ N3dst4:e.target将是click事件的初始目标(如果span.green有子节点,则可以是子节点)。在处理程序内部,应该使用this引用。看到这个小提琴
LeGEC

1
另一个要增加委派主题的注释-它既有用又非常有效。与将事件附加到每个匹配的元素相比,委派将消耗更少的浏览器资源。以为我提到了它,以防万一人们需要更多理由使用委派。
phatskat 2014年

6

第一种方法,$("div#target span.green").on()将单击处理程序直接绑定到在执行代码时与选择器匹配的跨度。这意味着,如果以后添加其他跨度(或更改其类以使其匹配),则它们将错过,并且将没有单击处理程序。这也意味着,如果您以后从某个跨度中删除“绿色”类,其单击处理程序将继续运行-jQuery不会跟踪处理程序的分配方式,而是检查选择器是否仍然匹配。

第二种方法,$("div#target").on()将点击处理程序绑定到匹配的div(同样,这与当时匹配的div相对),但是当在div中某处发生点击时,仅当单击时才运行处理程序功能不仅发生在div中,而且发生在与第二个参数.on()“ span.green”中的选择器匹配的子元素中。以这种方式执行时,创建这些子跨度并不重要,单击它们仍将运行处理程序。

因此,对于不是动态添加或更改其内容的页面,您不会注意到这两种方法之间的差异。如果要动态添加额外的子元素,则第二种语法意味着您不必担心将单击处理程序分配给它们,因为您已经在父项上完成了一次。


5

对N3dst4的解释是完美的。基于此,我们可以假定所有子元素都在主体内部,因此我们只需要使用以下内容:

$('body').on('click', '.element', function(){
    alert('It works!')
});

它适用于直接或委托事件。


2
jQuery建议不要使用body,因为它比较慢,因为脚本必须搜索body内部的所有子元素,在大多数情况下应该很多。最好(更快)使用元素的中间父容器。
mikesoft

1
jQuery删除了与您显示的相同的实时方法。这是性能较弱的,不应使用。
Maciej Sikora'9

在现代浏览器中,$('body').on()from的委托.element行为应document.body.addEventHandler()if (Event.target.className.matches(/\belement\b/))回调中的native行为完全相同。由于$.proxy开销,它在jquery中可能会稍微慢一些,但请不要在此引用我。
Cowbert

2

与OP相切,但是帮助我解决此功能混乱的概念是绑定元素必须是所选元素的父元素

  • 绑定是指剩余的内容.on
  • 选择是指的第二个参数.on()

委托不像.find()那样工作,它选择绑定元素的子集。选择器仅适用于严格的子元素。

$("span.green").on("click", ...

$("span").on("click", ".green", ...

特别是,要获得@ N3dst4的“将来创建的元素”提示的优势,绑定元素必须是永久父元素。然后,选定的孩子可以来去去。

编辑

为何.on不起作用的清单

棘手的原因为何$('.bound').on('event', '.selected', some_function)不起作用:

  1. 绑定元素不是永久的。它是在调用后创建的.on()
  2. 所选元素不是绑定元素的适当元素。这是相同的元素。
  3. Selected元素通过调用防止事件冒泡到绑定元素.stopPropagation()

(省略一些棘手的原因,例如选择器拼写错误。)


1

我写了一篇比较直接事件和委托的文章。我比较了纯js,但是它对于仅封装它的jquery具有相同的含义。

结论是委托事件处理用于动态DOM结构,在用户与页面交互时可以创建绑定元素(无需再次绑定),而直接事件处理用于静态DOM元素(当我们知道结构不会改变时)。

有关更多信息和完整比较 -http://maciejsikora.com/standard-events-vs-event-delegation/

使用总是委托的处理程序(我认为这是当前非常流行的方法)是不正确的,许多程序员使用它是因为“应该使用它”,但是事实是直接事件处理程序在某些情况下更好,并且应该选择使用哪种方法通过了解差异。


如果附加许多事件处理程序(例如,表的每一行),则在容器中使用单个委托处理程序而不是附加许多直接处理程序通常在性能上更好。您可以从以下基本事实中看到这一点:事件处理程序计数本身就是一个配置指标。
考伯特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.