【问题标题】:Event listeners get removed after adding/removing some elements of a list添加/删除列表的某些元素后,事件侦听器被删除
【发布时间】:2022-11-14 12:18:12
【问题描述】:

我有一个<ul> 列表,其中包含一些<li> 元素,并且我为每个元素添加了一个click 事件侦听器,以将单击的项目移动到列表顶部。

function add_event_listeners() {
    let elements = my_list.getElementsByTagName('li');
    for (let item of elements) {
        item.addEventListener("click", send_to_top);
    }
}

function send_to_top() {
    this.parentElement.children[0].insertAdjacentElement('beforebegin', this);
}

这段代码工作正常,直到我删除或添加一个新的li 到列表中,所有事件侦听器都被删除,之后的点击不起作用。

什么是正确的事件侦听器来检测新元素已从列表中添加或删除?那么之后我可以使用它来运行add_event_listeners() 函数吗?

基于 MDN 上的 HTMLCollection 文档:

HTML DOM 中的HTMLCollection 是活动的;它会自动更新 当基础文档更改时。出于这个原因,这是一个很好的 如果添加,制作副本的想法(例如使用Array.from)进行迭代, 移动或删除节点。

任何人都可以帮助提供如何做到这一点的代码示例吗?

【问题讨论】:

    标签: javascript dom addeventlistener removeeventlistener htmlcollection


    【解决方案1】:

    不知何故,我的工作只是重构代码,见下文:

    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <ul id="lists">
          <li class="list-item">
            <div>List #1</div>
            <button class="btn-send-up">Send to top</button>
          </li>
          <li class="list-item">
            <div>List #2</div>
            <button class="btn-send-up">Send to top</button>
          </li>
          <li class="list-item">
            <div>List #3</div>
            <button class="btn-send-up">Send to top</button>
          </li>
          <li class="list-item">
            <div>List #4</div>
            <button class="btn-send-up">Send to top</button>
          </li>
        </ul>
    
        <script>
          const listsEl = document.getElementById('lists');
    
          const addEventListeners = () => {
            const sendUpBtnEls = document.querySelectorAll('.btn-send-up');
    
            sendUpBtnEls.forEach((sendUpBtnEl) => {
              sendUpBtnEl.addEventListener('click', (e) => {
                const listItemEl = e.target.closest('.list-item');
    
                listsEl.firstElementChild.insertAdjacentElement(
                  'beforebegin',
                  listItemEl,
                );
              });
            });
          };
    
          addEventListeners();
        </script>
      </body>
    </html>
    

    【讨论】:

    • 谢谢@unspeakable29,但我忘了提到这个问题何时发生。当我在列表中添加一个新的li 或删除一个时,就会发生这种情况。我的意思是当 ul 元素的 HTML 更新时。
    • @JafarAbazeed 我明白了,如果它是新的 li 意味着您也必须将相同的事件附加到该元素。因为当前的事件侦听器只会附加到执行时已经在 DOM 中的那些 li。对于新元素,您必须再次将添加事件侦听器附加到它们。
    【解决方案2】:

    我避免使用MutationObserver 来捕获列表 HTML 中的任何更改,因为我认为这会很复杂并且会消耗性能。

    我能够使用以下代码来管理它:

    const observer = new MutationObserver( () => authors_list__add_listeners() );
    observer.observe(my_list, { childList: true });
    

    【讨论】:

      【解决方案3】:

      为了这个问题的未来观众的利益:

      您是否使用.innerHTML += 添加新内容?

      在发表此评论时(2022 年 11 月),破坏现有事件侦听器(甚至在不相关元素上)的罪魁祸首似乎是

      .innerHTML +=

      所以尝试使用不同的技术。

      例如,避免:

      HTML 插入技术 1(插入 HTML,但似乎无意中删除了其他不相关元素上的任何现有事件侦听器,因此不推荐):

      document.body.innerHTML += '&lt;div id="something"&lt;/div&gt;';

      相反,请使用以下(或其他一些技术):

      技术 2(有效且不影响现有事件侦听器):

      document.body.insertAdjacentHTML( 'beforeend','&lt;div id="something"&lt;/div&gt;');

      ...或任何其他方式(例如append 等)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-10
        • 2012-07-18
        • 2011-08-27
        • 1970-01-01
        • 1970-01-01
        • 2022-08-03
        • 1970-01-01
        相关资源
        最近更新 更多