【问题标题】:jQuery .on() delegation with selector that matches nested elements带有匹配嵌套元素的选择器的 jQuery .on() 委托
【发布时间】:2015-12-08 00:38:24
【问题描述】:

// Example A
$("#delegate").on("click", function(event) {
  // executes on click on any descendant of #delegate or self (not a delegate at all)
  // 'this' is #delegate
});


// Example B
$("#delegate").on("click", "#outer", function(event) {
  // executes on click on any descendant of #outer or self
  // 'this' is #outer or #inner (depends on the actual click)
});

$("#delegate").on("click", "#inner", function(event) {
  // executes on click on any descendant of #inner or self (nothing happens when clicking #outer)
  // 'this' is #inner
});


// Example C (now it's getting weird)
$("#delegate").on("click", "div", function(event) {
  // executes twice, when clicking #inner, because the event passes #outer when bubbling up

  // one time 'this' is #inner, and the other time 'this' is #outer
  // stopPropagation() // actually prevents the second execution
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="delegate">
  <div id="outer">
    outer
    <div id="inner">
      inner
    </div>
  </div>
</div>

你如何从逻辑上解释这种行为?

恰好有一个点击事件,从#inner开始,经过#outer冒泡,最后到达#delegate

#delegate 的 on-handler (准确地)捕获了一次事件。处理程序检查事件的历史记录是否包含任何 div 元素。

如果适用,回调函数应该被调用一次。这就是我所期望的。 “单个事件,单个处理程序,单个条件,单个回调”。

如果你看一下stopPropagation() 的行为,它会变得更加疯狂。您实际上可以避免第二次执行,尽管事件已经到达#delegatestopPropagation(不应该在这里工作。

on-delegation 逻辑的实现有什么“魔法”?事件冒泡和程序流是否以任何方式分开?

请不要一开始就发布“实用建议”(“改用 xyz!”)。我想了解为什么代码会以它的方式工作。

【问题讨论】:

  • 您在第二次和第三次通话中错过了click 事件。
  • 您是否只询问最后一种情况,委托给div
  • 谢谢。我刚刚将点击事件添加到我的帖子中。是的:基本上我只是在问最后一个案例。
  • 您的问题是什么? “你如何从逻辑上解释这种行为?”好吧,#delegate 中有两个&lt;div&gt;s,并且将一个单击事件附加到其中的所有 div 将因此在单击#inner 时触发 2 个事件。当然使用 stopPropagation 可以防止从#inner 冒泡到#outer
  • 所以事件不会冒泡到#delegate 然后执行回调? Instad 处理程序/回调实际上附加到特定的 div?

标签: javascript jquery jquery-events delegation event-bubbling


【解决方案1】:

因为您以两种方式在所有 div 上绑定事件:

  1. 使用元素div的id属性。
  2. 使用元素div的标签名。

所以如果你在最后一个 event.stopPropagation(); 上仍然会出现两次警报,因为你点击了 div 和 #inner (例如。)

检查下面的sn-p。

$("#delegate").on("click", function(event) {
  alert(this.id);
});

/*
$("#delegate").on('click', "#outer", function(event) {
  alert(this.id);
});

$("#delegate").on('click', "#inner", function(event) {
  alert(this.id);
});

*/
// now it's getting weird
$("#delegate").on("click", "div", function(event) {
  event.stopPropagation();
  alert(this.id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="delegate">
  <div id="outer">
    outer
    <div id="inner">
      inner
    </div>
  </div>
</div>

【讨论】:

  • 抱歉 - 我忘了告诉我 sn-p 中所有不同的 .on() 调用都是不同的示例,并且不是同时设置的。 “现在越来越奇怪了”-call 是你真正需要的唯一一个。
【解决方案2】:

事件委托的工作方式是 jQuery 从最内层的目标遍历 DOM 树到委托绑定的元素,测试每个元素以查看它是否与选择器匹配。如果是,它会执行带有this 绑定到该元素的处理程序。

event.stopPropagation 被调用时,它会在event 对象中设置一个标志。遍历 DOM 树的循环也调用event.isPropagationStopped()。如果传播停止,它会跳出循环。

换句话说,jQuery 在实现委托时会进行自己的冒泡和传播停止,它没有使用浏览器的冒泡(除了这个冒泡对于在#delegate 上触发的初始事件是必要的,因此jQuery 循环将运行)。

【讨论】:

  • Hm... 似乎对“jQuery 在浏览器冒泡之外/之前自己冒泡”的理解是我缺少的提示。谢谢你。 ;)
  • jQuery 不会添加其“自己的”冒泡。它为不支持它的浏览器添加冒泡,例如 IE8 的 change 事件。
  • 我想我误解了那部分代码。但它仍然会自行检查stopPropagation
【解决方案3】:

一切都按预期进行。看看this fiddle

$("#delegate").on("click", "div", function(event) {
  // event.stopPropagation();
  alert('div: ' + $(this).attr('id'));
});

单击#inner 将触发上述事件。该事件将冒泡到#outer,因为#inner#outer 的后代。由于#outer 也是&lt;div,因此该事件也将在#outer 上触发。从逻辑上讲,点击#inner 会先提示“div:inner”,然后是“div:outer”。

调用event.stopPropagation() 告诉事件不要冒泡,所以#outer 保持未被调用。

this fiddle以外的:

<div id="delegate">
  <div id="first">
    first
  </div>
  <div id="second">
    second
      <div id="third">
        third, inside second
      </div>
    </div>
</div>

点击第三个会先提示third,然后是second,然后停止,因为#first不是父级而是兄弟级。

【讨论】:

    猜你喜欢
    • 2012-12-18
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-17
    • 2012-01-15
    • 1970-01-01
    相关资源
    最近更新 更多