【问题标题】:add event listener on elements created dynamically在动态创建的元素上添加事件监听器
【发布时间】:2012-12-24 21:23:42
【问题描述】:

是否可以为所有动态生成的元素添加事件监听器(Javascript)? 我不是该页面的所有者,因此无法以静态方式添加侦听器。

对于我使用的页面加载时创建的所有元素:

doc.body.addEventListener('click', function(e){
//my code
},true);

当页面上出现新元素时,我需要一种方法来调用此代码,但我无法使用 jQuery(委托、on 等无法在我的项目中工作)。我该怎么做?

【问题讨论】:

    标签: javascript addeventlistener dom-events intercept


    【解决方案1】:

    听起来您需要采用委托策略,而不是退回到图书馆。我在这里的小提琴中发布了一些示例代码:http://jsfiddle.net/founddrama/ggMUn/

    它的要点是使用event 对象上的target 来查找您感兴趣的元素,并做出相应的响应。比如:

    document.querySelector('body').addEventListener('click', function(event) {
      if (event.target.tagName.toLowerCase() === 'li') {
        // do your action on your 'li' or whatever it is you're listening for
      }
    });
    

    CAVEATS! 示例 Fiddle 仅包含符合标准的浏览器的代码(即 IE9+,以及几乎所有其他版本)如果您需要支持“旧 IE”attachEvent ,那么您还需要围绕适当的本机函数提供自己的自定义包装器。 (关于这个有很多很好的讨论;我喜欢 Nicholas Zakas 在他的书Professional JavaScript for Web Developers中提供的解决方案。)

    【讨论】:

    • @JianWeihang 你能澄清你的问题吗?您不希望将元素直接应用于body 元素(例如,作为onclick 属性),否则会冒着将已经存在的听众吹走的风险。事件委托策略更加安全:不太可能干扰或破坏元素上的其他侦听器,并且不太可能占用每个元素侦听器的内存。
    • 很好的答案,我想知道不只是 document.body === document.querySelector('body') 吗?这就是为什么在这两种情况下,您总是将点击处理程序附加到唯一的一个正文元素。
    • @dinchev 是的,它们都是等价的。在给出示例时,我更喜欢使用document.querySelector() 版本,因为这样更容易概括——也就是说,并非每个元素都可以从document 作为属性访问。
    • 如果我的活动是focus,它似乎不起作用。我该怎么办?
    • @ColorWin 你需要使用event capturing
    【解决方案2】:

    取决于你如何添加新元素。

    如果你使用createElement添加,你可以试试这个:

    var btn = document.createElement("button");
    btn.addEventListener('click', masterEventHandler, false);
    document.body.appendChild(btn);
    

    然后你可以使用masterEventHandler()来处理所有的点击。

    【讨论】:

    • 我不是添加元素的页面的所有者,所以我不知道元素的插入方式。
    • 迄今为止的最佳答案。
    • 我在这个答案中看到的问题是,当/如果删除底层元素时,事件侦听器仍将保留在内存中。这是因为对btn 的引用仍然存在。在这种情况下,选择的答案是更好的答案。 See here 了解更多信息。
    【解决方案3】:

    这里值得注意的一个晦涩问题也可能是我刚刚发现的这个事实:

    如果一个元素将z-index 设置为-1 或更小,您可能会认为 侦听器没有被绑定,实际上它是,但是浏览器 认为您正在点击更高的z-index 元素。

    在这种情况下,问题不在于侦听器未绑定,而是它无法获得焦点,因为其他东西(例如,可能是隐藏元素)位于您的元素之上,而重点是什么(意思是:事件没有被触发)。幸运的是,您可以通过右键单击元素,选择“检查”并检查您单击的内容是否是正在“检查”的内容来轻松检测到这一点。

    我用的是Chrome,不知道其他浏览器有没有这么受影响。但是,它很难找到,因为从功能上讲,它在大多数方面类似于监听器未绑定的问题。我通过从 CSS 中删除以下行来修复它:z-index:-1;

    【讨论】:

      【解决方案4】:

      我创建了一个小函数来添加动态事件侦听器,类似于jQuery.on()

      它使用与接受的答案相同的想法,只是它使用Element.matches() 方法来检查目标是否与给定的选择器字符串匹配。

      addDynamicEventListener(document.body, 'click', '.myClass, li', function (e) {
          console.log('Clicked', e.target.innerText);
      });
      

      from github可以获取。

      【讨论】:

        【解决方案5】:

        当您必须只支持“现代”网络浏览器(不是 Microsoft Internet Explorer)时,mutation observers 是完成此任务的正确工具:

        new MutationObserver(function(mutationsList, observer) {
            for(const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    // put your own source code here
                }
            }
        }).observe(document.body, {childList: true, subtree: true});
        

        【讨论】:

          【解决方案6】:

          将匿名任务委托给动态创建的HTML elementsevent.target.classList.contains('someClass')

          1. 返回truefalse
          2. 例如。
          let myEvnt = document.createElement('span');
          myEvnt.setAttribute('class', 'someClass');
          myEvnt.addEventListener('click', e => {
            if(event.target.classList.contains('someClass')){ 
              console.log(${event.currentTarget.classList})
          }})
          
          1. 参考:https://gomakethings.com/attaching-multiple-elements-to-a-single-event-listener-in-vanilla-js/
          2. 好读:https://eloquentjavascript.net/15_event.html#h_NEhx0cDpml
          3. MDN : https://developer.mozilla.org/en-US/docs/Web/API/Event/Comparison_of_Event_Targets
          4. 插入点:

          【讨论】:

            【解决方案7】:

            您可能想看看这个库:https://github.com/Financial-Times/ftdomdelegate,它是 1,8K gzipped

            它用于绑定到与给定选择器匹配的所有目标元素上的事件,无论在注册时 DOM 中是否存在任何内容。

            你需要导入脚本,然后像这样实例化它:

              var delegate = new Delegate(document.body);
              delegate.on('click', 'button', handleButtonClicks);
            
              // Listen to all touch move
              // events that reach the body
              delegate.on('touchmove', handleTouchMove);
            
            });
            
            
            

            【讨论】:

              【解决方案8】:

              使用classList属性一次绑定多个类

              var container = document.getElementById("table");
              container.classList.add("row", "oddrow", "firstrow");
              

              【讨论】:

              • 事件监听器不是类。
              猜你喜欢
              • 1970-01-01
              • 2021-08-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-11-24
              • 1970-01-01
              • 2016-05-06
              • 2021-06-24
              相关资源
              最近更新 更多