直接与委托 - jQuery .on()

IT技术 javascript jquery event-bubbling jquery-events event-binding
2021-01-30 21:02:03

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

selector提供 a 时,事件处理程序被称为delegated当事件直接发生在绑定元素上时,不会调用处理程序,而是仅针对与选择器匹配的后代(内部元素)调用。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");
});

也许有人可以参考一个不同的例子来澄清这一点?谢谢。

6个回答

案例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中,只有容器被给予指令;它负责代表其子元素注意到点击捕捉事件的工作已经下放这也意味着将针对将来创建的子元素执行该指令。

那么为什么on()允许两个参数与 using 几乎相同click()呢?
2021-03-10 21:02:03
@newbie, @N3dst4 :e.target将是点击事件的初始目标(如果span.green子节点可以是子节点)。从处理程序内部,您应该使用this引用。看到这个小提琴
2021-03-12 21:02:03
.on() 是一个通用 API,可以处理任何类型的事件,包括多个不同的事件(您可以在第一个字符串中放置多个事件名称。) .click() 只是第一种形式的简写。
2021-03-26 21:02:03
这是一个很好的解释,并使我长期以来拒绝理解的问题变得清晰。谢谢!
2021-03-31 21:02:03
添加到委托主题的另一个注意事项 - 它非常有用且非常有效。与将事件附加到每个匹配元素相比,通过委托,您将使用更少的浏览器资源。我想我会提到它,以防万一人们需要更多的理由来使用委托。
2021-04-08 21:02:03

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

第二种方式,$("div#target").on()将点击处理程序绑定到匹配的 div(同样,这是针对那些匹配的),但是当在 div 中的某处发生点击时,处理程序函数只会在点击时运行不仅发生在 div 中,而且发生在与第二个参数中的选择器匹配的子元素中.on(),“span.green”。以这种方式完成这些子跨度的创建时间无关紧要,单击它们仍将运行处理程序。

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

N3dst4的解释很完美。基于此,我们可以假设所有子元素都在 body 内部,因此我们只需要使用这个:

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

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

Jquery 删除了与您显示的功能相同的实时方法。这是性能较弱的,不应使用。
2021-03-20 21:02:03
在现代浏览器中,$('body').on()来自委托的.element行为应该document.body.addEventHandler()if (Event.target.className.matches(/\belement\b/))在回调中使用 an的本机完全相同由于$.proxy开销,它在 jquery 中可能会稍微慢一些,但不要引用我的话。
2021-03-20 21:02:03
jquery 建议不要使用 body,因为它速度较慢,因为脚本必须搜索 body 内的所有孩子,这在大多数情况下应该很多。最好(更快)使用元素的中间父容器。
2021-03-26 21:02:03

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

  • Bound 指的是.on.
  • Selected 是指 的第二个参数.on()

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

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

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

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

编辑

为什么委派.on不起作用的清单

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

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

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

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

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

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

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

如果附加许多事件处理程序(例如,表的每一行),使用单个委托处理程序到容器而不是附加许多直接处理程序通常会提高性能。您可以从事件处理程序计数本身就是一个分析指标这一基本事实中看出这一点。
2021-03-15 21:02:03