[英]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 上绑定事件:
所以如果你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.