祖先的事件处理程序可以停止其子元素事件之一的传播吗?

Posted

技术标签:

【中文标题】祖先的事件处理程序可以停止其子元素事件之一的传播吗?【英文标题】:Can an ancestor's event handler stop propagation for one of its child element's events? 【发布时间】:2014-01-28 16:47:54 【问题描述】:

我希望有人能帮助我理解为什么下面的场景会失败。我有一个带有事件处理程序的父 ul 标记,该处理程序为嵌套在其中的另一个 ul 标记中的给定后代 li 元素提供条件。标记是:

<ul id="outerUL">
    <li>LIST ITEM 1</li>
    <li>LIST ITEM 2</li>
    <li>
        <ul id="innerUL">
            <li>LIST ITEM 3</li>
            <li>LIST ITEM 4</li>
            <li>
                <ul id="inMostUL">
                    <li>LIST ITEM 5</li>
                    <li>LIST ITEM 6</li><!-- we condition for this element -->
                    <li>LIST ITEM 7</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

javascript 是:(似乎祖先调用中的条件 .stopPropagation() 失败...)

var outerMostUL = document.getElementById("outerUL");
outerMostUL.addEventListener('click', 
    function(e)

        if(e.target.innerhtml === "LIST ITEM 6")
           e.stopPropagation();
           alert("you clicked LIST ITEM 6. Event travel stops.");
           // return; // a return WILL work
        

     // below runs if propagation continues...
     alert("outerMostUL event handler fired!");

    ,
    false);

现在,如果我决定对该 li 标签进行谨慎的 .addEventListener() 调用,则 .stopPropagation() 会按预期工作,例如:

// A discreet event handler does work
var inMostUL = document.getElementById("inMostUL");
inMostUL.children[1].addEventListener('click', function(e)

    e.stopPropagation();
    alert("The descendent event fires, but stops now.");

);

所以我的问题是:如果启用了冒泡,您是否应该能够在祖先的处理程序中为给定的 e.target 使用条件并停止其事件的传播?似乎一个元素必须有自己的处理程序绑定来发起一个事件,但也许我混淆了传播祖先链的传播事件与通过该方法实际添加事件侦听器。任何光脱落将不胜感激。我只是想通过简单的例子来概念化 js 事件处理。感谢您对此的任何考虑。

【问题讨论】:

【参考方案1】:

事件冒泡传播可以在祖先链上的任何点使用e.stopPropagation() 停止,这将阻止事件进一步传播到其他祖先。

而且,仅在某些情况下有条件地停止传播是没有问题的。


我认为您的一些困惑只是与您的 javascript 函数有关,而不是与传播有关。在这段代码中:

var outerMostUL = document.getElementById("outerUL");
outerMostUL.addEventListener('click', function(e)
   if(e.target.innerHTML === "LIST ITEM 6")
       e.stopPropagation();
       alert("you clicked LIST ITEM 6. Event travel stops.");
   
   // below runs ALWAYS, regardless of the result of the previous "if" statement
   alert("outerMostUL event handler fired!");
, false);

在没有return 语句的情况下发生第二个警报不是因为传播,​​而是因为您的javascript 函数在条件if 块之后继续执行。这与传播无关,而与 javascript 程序流程有关。如果您添加 return 语句,您将提前结束您的事件处理程序回调,因此其余部分不会执行。如果没有return 语句,无论if 语句是否满足,该函数中的执行都会在if 块之后继续。


在从概念上理解事件传播时,只需考虑浏览器中的一段代码,它会启动一个冒泡事件。该事件首先发送到目标对象的事件处理程序,如果在那里没有取消传播,则将其发送到下一个祖先,如果在那里没有取消传播,则向上发送祖先链,直到它到达document 对象或直到传播被取消。


另外,请记住,如果您不使用像 jQuery 这样的跨平台库,并且想要支持旧版本的 IE,那么在这些旧版本的 IE 中停止传播的工作方式会有所不同。

【讨论】:

添加 e.cancelBubble = true; 以获得旧版 IE 支持,除非您使用 jQuery,在这种情况下,jQuery 会为您处理。

以上是关于祖先的事件处理程序可以停止其子元素事件之一的传播吗?的主要内容,如果未能解决你的问题,请参考以下文章

jquery事件冒泡

停止鼠标事件传播

不同事件的角停止传播

事件流和事件委托

如何在自定义事件中停止事件传播/冒泡

微信小程序组件——bindtap和catchtap的区别