【问题标题】:Why does event.stopPropagation() stop multiple matched elements in delegated events?为什么 event.stopPropagation() 会停止委托事件中的多个匹配元素?
【发布时间】:2016-08-04 17:18:50
【问题描述】:

当使用委托事件时,所有匹配的元素都会触发该事件,因为它会从目标中冒出。

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

这可以在https://jsfiddle.net/bLw7ch50/1/ 中看到,例如,单击 div 4 会触发 3 个警报。对于 div-4、div-2 和 div-one。

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

  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. 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
  });
});

【问题讨论】:

  • 因为...要发生委托事件,该事件必须传播到委托目标...如果您在此过程中停止任何处理程序上的传播,它将不会传播。跨度>
  • ..Umm 传播到body 后没有更多传播了吗?你是说事件再次传播到body
  • 它只传播一次到文档,然后再次返回。它不会从中间的每个元素重新开始,只有一个事件。如果你停止它,它就会停止。
  • 等一下,首先,“它只传播一次到文档,然后再返回”是什么意思?事件从文档到目标,然后备份不是吗?而且,如果只有 1 个事件,为什么没有 event.stopPropagation() 它会触发 3 次?
  • 是的,与我所说的相反,:) 它触发了三次,因为符合事件条件的三个元素是委托目标的后代(并且在事件链中,或者你称之为. 原始目标和委托目标之间的元素。)

标签: javascript jquery events event-delegation


【解决方案1】:

这一切都发生在 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。如果您单击第二个,两个处理程序将以正确的顺序为每个框 div 调用一次。


很遗憾,我找不到任何文档来支持这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多