繁体   English   中英

jQuery .on() 委托与匹配嵌套元素的选择器

[英]jQuery .on() delegation with selector that matches nested elements

 // 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 #delegate (恰好)一次。 处理程序检查事件的历史记录是否包含任何 div 元素。

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

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

在委托逻辑的实现中做了什么样的“魔法”? 事件冒泡和程序流是否以任何方式分开?

请不要首先发布“实用建议”(“请改用 xyz!”)。 我想了解为什么代码的工作方式如此。

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

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

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

检查下面的片段。

 $("#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>

事件委托的工作方式是 jQuery 从最里面的目标到委托绑定的元素沿着 DOM 树向上走,测试每个元素以查看它是否与选择器匹配。 如果是,则执行将this绑定到该元素的处理程序。

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

换句话说,jQuery 在实现委托时正在做自己的冒泡和传播停止,它没有利用浏览器的冒泡(除了这种冒泡是在#delegate上触发初始事件所#delegate ,因此 jQuery 循环将跑)。

一切都按预期工作。 看看这个小提琴

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

单击#inner将触发上述事件。 该事件将气泡高达#outer因为#inner是的后代#outer 由于#outer也是一个<div ,事件也将在#outer#outer 从逻辑上讲,点击#inner将首先提示“div:inner”,然后是“div:outer”。

调用event.stopPropagation()告诉事件不要冒泡,因此#outer保持未#outer状态。

除了这个小提琴

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM