【问题标题】:determine event path in DOM Event bubbling确定 DOM 事件冒泡中的事件路径
【发布时间】:2014-11-29 11:09:32
【问题描述】:

我试图找出事件冒泡的路径。例如,我有一个标记像

 <div id="container" onclick="func">
        <div id="div1"></div>
        <div id="div2">
            <div id="div2.1"></div>
            <span id="span2.2"></span>
            <div id="div2.3">
                <button id="btn2.3.1"></button>
            </div>
        </div>
    </div>

现在,如果单击 btn2.3.1,我希望看到事件冒泡的整个路径,即 btn2.3.1 -> div2.3 -> div2 ->container 。有没有办法只在容器上放置一个处理程序? (请不要使用 Jquery)

我找到了一个 event.path 数组。这是什么东西,但找不到更多关于它的详细信息。它是跨浏览器的吗?实现这一目标的正确方法是什么?

【问题讨论】:

    标签: javascript html dom


    【解决方案1】:

    event.path || event.composedPath()

    event.path

    通过polymer project documentation 和通过an HTML5Rocks article 中的注释Dis/Un-covered,pathArray 形式的家谱。

    它似乎是event 接口的扩展”仅通过 Web ComponentShadow DOM 公开,并且是标准 仅在这方面(显然),似乎没有很多可用的文档,并且它没有在所有浏览器中(默认情况下)公开。

    event.composedPath() 救援!

    另一个question about the use of pathanswered with a suggestion to use composedPath...

    MDNdocumentation about event.composedPath()是这样描述的:

    Event 接口的composedPath() 方法返回事件的路径,该路径是一个对象数组,将在其上调用侦听器。如果影子根是在其 ShadowRoot.mode 关闭的情况下创建的,则这不包括影子树中的节点。

    WHATWGtheir "DOM specs" documentation about the "event path"中描述如下:

    返回事件的路径的invocation target对象(将在其上调用侦听器的对象),除了shadow trees中的任何nodes,其中shadow rootmode已“关闭”,无法从事件的 currentTarget 访问。

    Can I use... 表示 browser support of composedPath() 很普遍,IE 和 Edge 落后,没有可预见的支持,MDN 同意。

    WHATWG's documentation about "dispatching events" 详细说明了“事件的path”将具有项目appended 的条件。

    详情正确,2019 年 9 月 25 日

    实用演示

    const green = document.getElementById( 'green' ),
          msg = document.querySelector( 'output' );
    
    document.getElementById( 'red' ).addEventListener( 'click', evt => {
      msg.innerHTML = '"' + evt.target.id + '" got poked, and "green" was' +
      
      /* access to the event path */
      ( ~evt.composedPath().indexOf( green ) ? '' : "<b>n't</b>" )
      
      + ' in the path.';
    } );
    div { display: inline-block; padding: 1em 3em 1em 1em; cursor: pointer }
    output { font-family: monospace; display: block; margin-top: 1em }
    #red { background: red }
    #green { background: green }
    #blue { background: blue }
    <div id="red">
      <div id="green">
        <div id="blue"></div>
      </div>
    </div>
    <output>Poke the DOM!</output>

    【讨论】:

    • 这正是我一直在寻找的答案
    • 这在 Chrome 中效果很好,但似乎还没有在 Firefox 或 IE 中实现?还是我错过了什么?
    • @AdrianSchmidt 不,你没有错过一些东西。无赖吧?是的。
    • event.path 不是标准的。引用中的event path 就像在调度事件时创建的局部变量。但并未在活动中曝光。
    • @FredGandt 我也没有在 Shadow DOM 草案中看到 path 的定义。有一个deepPath 方法,但它做了一些不同的事情。
    【解决方案2】:
    function handleClicks(e) {
        var path = [];
        var node = e.target;
        while(node != document.body) {
           path.push(node);
           node = node.parentNode;
        }
        console.log(path);
    }
    
    document.body.addEventListener('click', handleClicks);
    

    【讨论】:

    • 所以除了循环之外别无他法??
    • 是的,我认为没有其他相同的性能和内存成本方式
    • 部分浏览器(Chrome)现在支持event.path属性,即事件传播路径NodeList
    • 将其添加为 polyfill 的最佳方法是什么?
    • 如果元素不是彼此的子元素,但例如基于绝对定位重叠,则此解决方案将不起作用。
    【解决方案3】:

    我有一个类似的要求,我正在收听文档上的事件并想知道该事件是否源自特定的 div。我通过添加并稍后检查 event.target 上的特定类名来处理它。

    var div1 = document.getElementById('div1');
    var div2 = document.getElementById('div2');
    
    document.addEventListener('click', function(e) {
      if (e.target.classList.contains('via-div1')) {
        alert('Event came through div1');
      } else if (e.target.classList.contains('via-div2')) {
        alert('Event came through div2');
      } else {
        alert('Event came from outside the divs');
      }
    });
    
    div1.addEventListener('click', function(e) {
      e.target.classList.add('via-div1');
    });
    
    div2.addEventListener('click', function(e) {
      e.target.classList.add('via-div2');
    });
    <div id="div1" style="background: #8bc34a"><span>div 1</span></div>
    <div id="div2" style="background: #00bcd4">
      <span>div 2</span>
      <div id="div2-1"><span>div 2-1</span></div>
      <button id="btn2-2">button 2-2</button>
    </div>

    【讨论】:

      【解决方案4】:

      现在有一个名为 event-propagation-path 的小型 GitHub 项目/NPM 模块,它充当 polyfill。在这里查看:

      event-propagation-path @ GitHub

      event-propagation-path @ NPM

      【讨论】:

        【解决方案5】:

        让我们假设我们在 HTML table 标记中查找事件路径。

        <tabe id="tab">
        .
        .
        .
        </table>
        

        以下 JavaScript 代码将在每个事件之后返回事件的元素。

        window.onload = function(){
        var tab = document.getElementById('tab');
        tab.onclick = function(event) {
        var target = getTargetElement(event);
        console.log(target);
        };
        }
        function getTargetElement(e) {
        e = e || window.event;
        return e.target || e.srcElement;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-22
          • 2017-02-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多