【问题标题】:stopPropagation vs. stopImmediatePropagationstopPropagation 与 stopImmediatePropagation
【发布时间】:2011-07-15 01:24:42
【问题描述】:

event.stopPropagation()event.stopImmediatePropagation() 有什么区别?

【问题讨论】:

  • 我鼓励读者不仅要坚持接受的答案,还要阅读其他答案,尤其是罗伯特·西默 (Robert Siemer) 的非常有启发性的答案。需要很好地了解传播的工作原理才能很好地理解它。

标签: javascript jquery


【解决方案1】:

stopPropagation 将阻止任何 处理程序执行 stopImmediatePropagation 将阻止任何父处理程序 以及 任何 其他 处理程序执行

来自jquery documentation: 的快速示例

$("p").click(function(event) {
  event.stopImmediatePropagation();
});

$("p").click(function(event) {
  // This function won't be executed
  $(this).css("background-color", "#f00");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>example</p>

注意这里事件绑定的顺序很重要!

$("p").click(function(event) {
  // This function will now trigger
  $(this).css("background-color", "#f00");
});

$("p").click(function(event) {
  event.stopImmediatePropagation();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<p>example</p>

【讨论】:

  • 您强调“父母”,但实际上如果在捕获阶段调用,两者也会停止进入孩子! See my answer for details.
  • 是否可以阻止其他处理程序但不能阻止父处理程序?
  • @AndrewFount 是的,如果您可以完全控制代码:将相关处理程序移至捕获阶段,该阶段位于冒泡阶段之前,并允许您在途中中断调用链下降(而不是上升)。
【解决方案2】:

一个小例子来演示这两种传播停止是如何工作的。

var state = {
  stopPropagation: false,
  stopImmediatePropagation: false
};

function handlePropagation(event) {
  if (state.stopPropagation) {
    event.stopPropagation();
  }

  if (state.stopImmediatePropagation) {
    event.stopImmediatePropagation();
  }
}

$("#child").click(function(e) {
  handlePropagation(e);
  console.log("First event handler on #child");
});


$("#child").click(function(e) {
  handlePropagation(e);
  console.log("Second event handler on #child");
});

// First this event will fire on the child element, then propogate up and
// fire for the parent element.
$("div").click(function(e) {
  handlePropagation(e);
  console.log("Event handler on div: #" + this.id);
});


// Enable/disable propogation
$("button").click(function() {
  var objectId = this.id;
  $(this).toggleClass('active');
  state[objectId] = $(this).hasClass('active');
  console.log('---------------------');
});
div {
  padding: 1em;
}

#parent {
  background-color: #CCC;
}

#child {
  background-color: #000;
  padding: 5em;
}

button {
  padding: 1em;
  font-size: 1em;
}

.active {
  background-color: green;
  color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">
  <div id="child">&nbsp;</div>
</div>

<button id="stopPropagation">Stop Propogation</button>
<button id="stopImmediatePropagation" ">Stop Immediate Propogation</button>

绑定了三个事件处理程序。如果我们不停止任何传播,那么应该有四个警报 - 三个在子 div 上,一个在父 div 上。

如果我们阻止事件传播,那么将有 3 个警报(全部在内部子 div 上)。由于事件不会向上传播 DOM 层次结构,因此父 div 不会看到它,它的处理程序也不会触发。

如果我们立即停止传播,那么只会有 1 个警报。即使有三个事件处理程序附加到内部子 div,也只会执行 1 个,并且任何进一步的传播都会立即终止,即使在同一个元素内也是如此。

【讨论】:

  • stopPropagation() 变体也将停止向下传播 DOM 层次结构。不只是起来。请check my answer了解捕获阶段的详细信息。
【解决方案3】:

令人惊讶的是,所有其他答案只说了一半或者实际上是错误的!

  • e.stopImmediatePropagation() 停止为此事件调用任何进一步的处理程序,没有例外
  • e.stopPropagation() 类似,但仍会在 此元素 上调用 此阶段 的所有处理程序(如果尚未调用)

什么阶段?

例如一个点击事件总是首先沿着 DOM 一路向下(称为“捕获阶段”),最后到达事件的起源(“目标阶段”),然后再次冒泡(“冒泡阶段”)。使用addEventListener(),您可以分别为捕获和冒泡阶段注册多个处理程序。 (目标阶段在目标上调用这两种类型的处理程序而不区分。)

这就是其他答案不正确的地方:

  • quote:“event.stopPropagation() 允许执行同一元素上的其他处理程序”
    • 更正:如果在捕获阶段停止,将永远无法到达气泡阶段处理程序,也会在同一元素上跳过它们
  • 引用:“event.stopPropagation() [...] 仅用于停止其相应父处理程序的执行”
    • 更正:如果在捕获阶段停止传播,则不会调用任何子级(包括目标)上的处理程序,而不仅仅是父级
    • ...并且:如果在冒泡阶段停止传播,则所有捕获阶段处理程序都已被调用,包括父级上的处理程序

fiddle 和 mozilla.org event phase 的演示说明。

【讨论】:

    【解决方案4】:

    event.stopPropagation 将阻止父元素上的处理程序运行。
    调用event.stopImmediatePropagation 也会阻止同一元素上的其他处理程序运行。

    【讨论】:

    • 值得一提的是,事件处理程序是按照它们附加到元素的顺序执行的。
    【解决方案5】:

    来自jQuery API

    除了保留任何额外的 元素上的处理程序 执行后,此方法也会停止 通过隐式调用冒泡 事件.stopPropagation()。简单来说 防止事件冒泡到 祖先元素,但允许其他元素 事件处理程序在同一个上执行 元素,我们可以使用 event.stopPropagation() 代替。

    使用 event.isImmediatePropagationStopped() 知道这种方法是否曾经 调用(在那个事件对象上)。

    简而言之:event.stopPropagation() 允许执行同一元素上的其他处理程序,而 event.stopImmediatePropagation() 阻止 每个 事件运行。

    【讨论】:

    • 可以肯定的是,event.stopImmediatePropagation 的原生 javascript 版本不会停止冒泡吧?
    • 确实,冒泡是当事件传播到父元素时,stopImmediatePropagation停止事件传播期间,它们都应该防止冒泡,你也可以改变模式为 capture,这将首先触发最外层的元素,然后才 down 到子 (冒泡是默认值,并且在相反的方向上工作)我>
    • 不准确,至少可以这么说。在捕获阶段停止将不允许在同一元素上的气泡处理程序与 explained in my answer. 一样执行
    【解决方案6】:

    我来晚了,但也许我可以用一个具体的例子说:

    假设你有一个&lt;table&gt;,有&lt;tr&gt;,然后是&lt;td&gt;。现在,假设您为&lt;td&gt; 元素设置了3 个事件处理程序,那么如果您在为&lt;td&gt; 设置的第一个事件处理程序中执行event.stopPropagation()那么&lt;td&gt; 的所有事件处理程序仍将运行,但该事件不会传播到&lt;tr&gt;&lt;table&gt;(也不会上升到&lt;body&gt;&lt;html&gt;documentwindow)。

    但是,现在,如果您在第一个事件处理程序中使用 event.stopImmediatePropagation(),那么 &lt;td&gt; 的其他两个事件处理程序将不会运行,并且不会传播到 @987654336 @、&lt;table&gt;(不会上升到 &lt;body&gt;&lt;html&gt;documentwindow)。

    请注意,它不仅适用于&lt;td&gt;。对于其他元素,将遵循相同的原则。

    【讨论】:

      【解决方案7】:

      1)event.stopPropagation(): =>它仅用于停止其相应父处理程序的执行。

      2) event.stopImmediatePropagation(): => 它用于停止执行其相应的父处理程序以及附加到自身的处理程序或函数,但当前处理程序除外。 => 它还会停止所有附加到整个 DOM 的当前元素的处理程序。

      示例如下:Jsfiddle!

      谢谢, -萨希尔

      【讨论】:

        【解决方案8】:

        这里有一个演示来说明区别:

        document.querySelectorAll("button")[0].addEventListener('click', e=>{
          e.stopPropagation();
          alert(1);
        });
        document.querySelectorAll("button")[1].addEventListener('click', e=>{
          e.stopImmediatePropagation();
          alert(1);
        });
        document.querySelectorAll("button")[0].addEventListener('click', e=>{
          alert(2);
        });
        document.querySelectorAll("button")[1].addEventListener('click', e=>{
          alert(2);
        });
        <div onclick="alert(3)">
           <button>1...2</button>
           <button>1</button>
        </div>

        请注意,您可以将多个事件处理程序附加到元素上的事件。

        【讨论】:

        • 所以这里的区别在于,由于div 是被点击的button 的父级,stopPropagation() 确保3 永远不会被提醒,而stopImmediatePropagation() 确保甚至在button 本身上注册的其他事件侦听器(即2)都不会被执行。
        • 我认为它最能代表差异,gj
        【解决方案9】:

        event.stopPropagation() 允许执行同一元素上的其他处理程序,而 event.stopImmediatePropagation() 阻止每个事件运行。例如,请参见下面的 jQuery 代码块。

        $("p").click(function(event)
        { event.stopImmediatePropagation();
        });
        $("p").click(function(event)
        { // This function won't be executed 
        $(this).css("color", "#fff7e3");
        });
        

        如果在前面的例子中使用了 event.stopPropagation,那么改变 css 的 p 元素上的下一个点击事件将会触发,但是如果是 event.stopImmediatePropagation() , 下一个 p 点击事件不会触发。

        【讨论】:

          【解决方案10】:

          在这里,我为 stopPropagation 与 stopImmediatePropagation 添加了我的 JSfiddle 示例。 JSFIDDLE

          let stopProp = document.getElementById('stopPropagation');
          let stopImmediate = document.getElementById('stopImmediatebtn');
          let defaultbtn = document.getElementById("defalut-btn");
          
          
          stopProp.addEventListener("click", function(event){
          	event.stopPropagation();
            console.log('stopPropagation..')
            
          })
          stopProp.addEventListener("click", function(event){
            console.log('AnotherClick')
            
          })
          stopImmediate.addEventListener("click", function(event){
          		event.stopImmediatePropagation();
              console.log('stopimmediate')
          })
          
          stopImmediate.addEventListener("click", function(event){
              console.log('ImmediateStop Another event wont work')
          })
          
          defaultbtn.addEventListener("click", function(event){
              alert("Default Clik");
          })
          defaultbtn.addEventListener("click", function(event){
              console.log("Second event defined will also work same time...")
          })
          div{
            margin: 10px;
          }
          <p>
          The simple example for event.stopPropagation and stopImmediatePropagation?
          Please open console to view the results and click both button.
          </p>
          <div >
          <button id="stopPropagation">
          stopPropagation-Button
          </button>
          </div>
          <div  id="grand-div">
            <div class="new" id="parent-div">
              <button id="stopImmediatebtn">
              StopImmediate
              </button>
            </div>
          </div>
          <div>
          <button id="defalut-btn">
          Normat Button
          </button>
          </div>

          【讨论】:

            猜你喜欢
            • 2014-12-05
            • 2011-01-03
            • 1970-01-01
            • 1970-01-01
            • 2013-06-09
            • 2011-02-13
            • 2013-05-02
            • 2023-03-31
            相关资源
            最近更新 更多