事件委托的工作方式是jQuery将DOM树从最内层的目标移动到委托所绑定的元素,测试每个元素以查看其是否与选择器匹配。如果是这样,它将使用绑定到该元素的this
执行处理程序。
// 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()
行为,它将变得更加疯狂。您实际上可以避免第二次执行,尽管事件已经到达#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
上触发初始事件是必要的,所以jQuery循环将运行)。
一切正常。看看this fiddle:
$("#delegate").on("click", "div", function(event) {
// event.stopPropagation();
alert('div: ' + $(this).attr('id'));
});
单击#inner
将触发上述事件。由于#outer
是#inner
的后代,因此事件将上升到#outer
。由于#outer
也是<div
,因此事件也会在#outer
上触发。逻辑上,单击#inner
将首先警告“ div:内部”,然后警告“ div:内部”。
呼叫event.stopPropagation()
会告诉事件不要冒泡,因此#outer
不会被调用。
[C0中以外:
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
不是父母,而是同级。
事件委托的工作方式是jQuery将DOM树从最内层的目标移动到委托所绑定的元素,测试每个元素以查看其是否与选择器匹配。如果是这样,它将使用绑定到该元素的this
执行处理程序。
一切正常。看看this fiddle: