使用委托(delegate)事件时,所有匹配元素都会在事件从目标冒泡时触发该事件。
基于https://learn.jquery.com/events/event-delegation/引用下面的 HTML 和 JS,单击 div-4 会在其冒泡时触发其所有祖先(div-1、div-2、div-3、body)上的单击事件。我将事件处理程序放在主体上,选择 :not(#div- Three)
这可以在 https://jsfiddle.net/bLw7ch50/1/ 中看到例如,单击 div 4 会触发 3 个警报。对于第四格、第二格和第一格。
我认为发生的事情是这样的:
- 点击
div-four
,触发div-four
的点击事件。 div-four
事件冒泡到div- Three
,触发div- Three
的点击事件。div-four
事件冒泡到div-two
,触发div-two
的点击事件。div-four
事件冒泡到div-one
,触发div-one
的点击事件。div-four
事件冒泡到body
,从body
触发点击事件。事件处理程序运行。报告target:div-four|current:div-four
。div-third
(来自步骤2)事件冒泡到body
。不触发事件处理程序。div-two
(来自第 3 步)事件冒泡到body
。事件处理程序运行。报告target:div-four|current:div-two
。div-one
(来自第 4 步)事件冒泡到body
。事件处理程序运行。报告target:div-four|current:div-one
。
如果在事件处理程序中调用 event.stopPropagation()
,则 div-four
事件会在第 5 步停止冒泡。(尽管上面没有任何冒泡 body
无论如何。)但是,步骤 2,3,4 中触发的事件应该仍然存在并冒泡,因此步骤 6,7,8 仍然会继续。
然而,事实似乎并非如此。以下https://jsfiddle.net/bLw7ch50/ ,取消注释 event.stopPropagation()
后,仅出现 1 个警报,target:div-four|current:div-four
。所以我可能在某个地方错了。我的理解有什么问题吗?
HTML:
<body>
<div id="div-one">
1st div
<div id="div-two">
2nd div
<div id="div-three">
3rd div
<div id="div-four">
4th div
</div>
</div>
</div>
</div>
<br/>
<br/>
<div id="output">
</div>
</body>
CSS:
div {
border: 1px solid;
}
Javascript(使用jquery1.9.1)
$(document).ready(function() {
$("body").on("click", ":not(#div-three)", function(event) {
var event_target = $(event.target).attr("id");
var event_current = $(event.currentTarget).attr("id");
$("#output").append("target:" + event_target +
"|current:" + event_current + "<br/>");
alert("target:" + event_target +
"|current:" + event_current);
// Commented out in https://jsfiddle.net/bLw7ch50/1/, exists in https://jsfiddle.net/bLw7ch50
event.stopPropagation(); // When this line is here, all other events stop
});
});
最佳答案
这一切都发生在 jQuery 的事件委托(delegate)中,它与事件冒泡的方式无关,只是 jQuery 试图模仿正常事件发生的情况。
对于普通的事件处理程序,如果您stopPropagation
,该事件将不再在树中冒泡,并且具有相同事件类型的处理程序的祖先将不会收到它。这与在使用事件委托(delegate)时用于决定是否应为元素调用事件处理程序的逻辑相同。
当您使用委托(delegate)绑定(bind)事件时,您仅将一个事件绑定(bind)到委托(delegate)目标。当事件处理程序(不是您的事件处理程序,jQuery 的内部事件处理程序)被触发时,jQuery 会查找原始事件目标和委托(delegate)目标之间的元素,然后根据选择器过滤这些元素,并按以下顺序调用它们的处理程序:原始事件目标到委托(delegate)目标。如果这些处理程序中的任何一个stopPropagation
,则合格事件目标列表中的其他元素都不会调用该处理程序。此过程中不会触发任何其他事件。
该系统还考虑其他委托(delegate)事件。
$(document).on('click', '.box1', function () {
console.log('first box1 handler');
});
$(document).on('click', '.box1', function (e) {
console.log('second box1 handler');
e.stopPropagation();
});
$(document).on('click', '.box2', function () {
console.log('first box2 handler');
});
$(document).on('click', '.box2', function (e) {
console.log('second box2 handler');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box1">
<div class="box1">
<div class="box1">
<div class="box1">
click here to begin
</div>
</div>
</div>
</div>
<div class="box2">
<div class="box2">
<div class="box2">
<div class="box2">
click here to begin without propagation
</div>
</div>
</div>
</div>
如果单击第一个框,您只会调用一次第一个处理程序和第二个处理程序,因为我们停止在最里面的 div 上传播。两者仍然会被调用,因为我们使用了 stopPropgation
而不是 stopImmediatePropagation
。如果单击第二个,两个处理程序都会以正确的顺序为每个框 div 调用一次。
不幸的是,我无法找到任何文档来支持这一点。
关于javascript - 为什么 event.stopPropagation() 会停止委托(delegate)事件中的多个匹配元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38773687/