【问题标题】:Is there a vanilla function to remove all event listeners without affecting the descendant nodes?是否有一个 vanilla 函数可以在不影响后代节点的情况下删除所有事件侦听器?
【发布时间】:2013-09-10 02:49:31
【问题描述】:

This question 本质上是我要问的,但有不删除后代节点事件的限制。

this fiddle 中,我尝试通过将附加的侦听器从 DOM 中移除并将其放回原处来移除它。

function removeListeners(el) {
    var par = el.parentNode;
    var place = el.nextSibling;
    par.removeChild(el);
    par.insertBefore(el, place);
}

不幸的是,这不起作用,您仍然可以单击以更改背景(这实际上很好,我从不知道您可以在元素不在 DOM 中的情况下附加事件)。

鉴于我尝试过的发现this

function removeListeners(el) {
    var par = el.parentNode;
    var clone = el.cloneNode(false);
    par.replaceChild(clone, el);

    for (var index = 0; index < el.childNodes.length; ++index)
        clone.appendChild(el.childNodes[index]);
}

它会尝试做一个浅层克隆,然后将所有后代复制回去,但它不会复制所有子代。

aforementioned question's answer 说“[如果你想让孩子们保留他们的听众] 你将不得不一次明确地移除一个听众”。我不知道你会如何实现它。
我假设他的意思是获取事件类型的列表并依次删除每个事件的侦听器 (like jQuery can)。这不仅对custom events 是不可能的,而且vanilla JS 有no such functionality(你必须指定要删除的函数)。

【问题讨论】:

    标签: javascript javascript-events


    【解决方案1】:

    Node.childNodes 不是一个数组,而是一个NodeList(参见NodeList on MDN)。它会在 DOM 更新时动态更新。

    在您的情况下,您在将元素移动到新的父节点时清空了 childNodes 集合。

    您可以使用Array.prototype.slice 将子节点复制到数组中,也可以向后迭代。

    function removeListeners(el) {
        var par = el.parentNode;
        var clone = el.cloneNode(false);
        par.replaceChild(clone, el);
    
        for (var index = el.childNodes.length - 1; index >= 0; --index)
            clone.insertBefore(el.childNodes[index], clone.childNodes[0]);
    }
    

    【讨论】:

    • 这是有道理的。所以如果我向后迭代它会起作用吗? I tried it,你说得对,点赞
    • 您可以向后迭代,但是在新克隆中以正确的顺序插入元素会很痛苦。像您在此处所做的那样将 childNodes 复制到一个数组更容易理解。
    • 哦,我指的是我的代码中的错误(显然不是浏览器)。在这种情况下,这绝对是一个错误
    • 好吧,我错了。将您的实现添加到我的答案中。
    【解决方案2】:

    我成功地进行了第二次尝试。
    然后,感谢@JulianDescottes 注意到我的疏忽,我制作了这个更简洁的版本。

    Here 是工作代码。

    function removeListeners(el) {
        //only replace the ancestor element
        var clone = el.cloneNode(false);
    
        //copy children backwards because of the removal
        for (var index = el.childNodes.length - 1; index >= 0; --index)
            clone.insertBefore(el.childNodes[index], clone.firstChild);
    
        //insert back into DOM
        el.parentNode.replaceChild(clone, el);
    }
    

    我希望有更原生的东西,我担心使用这种方法会产生无法预料的后果,我不喜欢从 DOM 中删除东西并期望它们在之后正常工作。
    至少它比当前的建议更有效,如果有人提出更好的建议,我将有义务(并感谢)接受您的回答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-20
      • 2017-09-14
      • 2018-06-29
      • 1970-01-01
      • 2022-12-14
      • 2018-08-04
      相关资源
      最近更新 更多