是否有一个vanilla函数来删除所有事件侦听器而不影响后代节点?

时间:2013-09-06 05:16:56

标签: javascript javascript-events

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(你必须指定要删除的函数)。

2 个答案:

答案 0 :(得分:5)

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

在您的情况下,当您将元素移动到新的parentNode时,您正在清空childNodes集合。

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

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]);
}

答案 1 :(得分:0)

我设法让我的第二次尝试工作 然后,感谢@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中移除东西并希望它们能够在之后正常工作。
至少它比当前的建议更有效率,如果有人想出更好的东西,我将不得不(并且感谢)接受你的回答。