javascript - 为什么 event.stopPropagation() 会停止委托(delegate)事件中的多个匹配元素?

标签 javascript jquery events event-delegation

使用委托(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 个警报。对于第四格、第二格和第一格。

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

  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-third(来自步骤2)事件冒泡到body。不触发事件处理程序。
  7. div-two(来自第 3 步)事件冒泡到 body。事件处理程序运行。报告target:div-four|current:div-two
  8. 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/

相关文章:

javascript - 我怎样才能弄清楚 Javascript 在哪里改变了我的注意力

javascript - Accordion jQuery - 一次打开一个元素并关闭其他元素

jquery - 如何使用 jQuery 查找所有具有 title 属性的元素?

android - 一键事件使所有 subview 进入按下状态

vue.js - 使用 v-on 对象语法传递事件修饰符

javascript - 为什么 onclick 触发下一个函数没有分配给它?

javascript - HTML 图像映射与多个 div 元素

javascript - 如何在 Javascript 中使用 PHP 中的 JSON 数据(数组)

Javascript - 将图像导出到Excel

javascript - 根据数组内容预选择复选框