为什么event.stopPropagation()会停止委派事件中的多个匹配元素

Why does event.stopPropagation() stop multiple matched elements in delegated events?

本文关键字:元素 事件 委派 stopPropagation event 为什么      更新时间:2023-09-26

使用委托事件时,所有匹配的元素都会在事件从目标弹出时触发该事件。

基于https://learn.jquery.com/events/event-delegation/参考下面的HTML和JS,点击div four会在它冒泡时触发所有祖先(div一、div二、div三、body)的点击事件。我将事件处理程序放在主体上,选择:not(#div-three)

这可以在https://jsfiddle.net/bLw7ch50/1/例如,单击div 4会触发3个警报。对于div四,div二和div一。

我认为发生的事情是这样的:

  1. 点击div-four,点击div-four触发的事件
  2. div-four事件气泡到div-three,点击div-three事件触发
  3. div-four事件气泡到div-two,点击div-two事件触发
  4. div-four事件气泡到div-one,点击div-one事件触发
  5. div-four事件气泡到body,点击事件从body触发。事件处理程序运行。报告target:div-four|current:div-four
  6. div-three(来自步骤2)事件冒泡到body。不触发事件处理程序
  7. CCD_ 19(来自步骤3)事件气泡到CCD_ 20。事件处理程序运行。报告target:div-four|current:div-two
  8. CCD_ 22(来自步骤4)事件气泡到CCD_ 23。事件处理程序运行。报告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的事件委派中,除了jQuery试图模仿正常事件之外,它与事件气泡的方式无关。

使用普通的事件处理程序,如果stopPropagation,则该事件将不再出现在树中,并且具有相同事件类型的处理程序的祖先将不会接收到它。这与在使用事件委派时用于决定是否应为元素调用事件处理程序的逻辑相同。

使用委派绑定事件时,只将一个事件绑定到委派目标。当触发事件处理程序(不是您的事件处理程序,而是jQuery的内部处理程序)时,jQuery会查看原始事件目标和委托目标之间的元素,然后根据选择器筛选这些元素,并按从原始事件目标到委托目标的顺序调用它们上的处理程序。如果这些处理程序中的任何一个stopPropagation,则合格事件目标列表中的任何其他元素都不会调用该处理程序。在此过程中不会触发其他事件。

该系统还考虑了其他委托事件。

$(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。如果单击第二个,两个处理程序将按正确顺序为每个boxdiv调用一次。


不幸的是,我找不到任何支持这一点的文档。