4

This question is essentially what I'm asking but with the restriction of not removing events for the descendant nodes.

In this fiddle I attempt to remove attached listeners by removing it from the DOM and placing it back.

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

Unfortunately this didn't work, you can still click to get the background to change (which is actually good, I never knew you could attach events without the element being in the DOM).

Given that discovery I tried 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]);
}

Which tries to do a shallow clone then copy all the decendants back in, but it doesn't copy all the children.

The aforementioned question's answer said that "[if you want to have the children keep their listeners] you'll have to resort to explicitly removing listeners one at a time". I don't know how you would implement that.
I assume he means getting a list of the event types and removing the listeners for each in turn (like jQuery can). Not only would that be impossible for custom events but vanilla JS has no such functionality (you must specify the function to remove).

4

2 回答 2

5

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

在您的情况下,当您将元素移动到新的父节点时,您正在清空 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]);
}
于 2013-09-06T05:58:37.820 回答
0

我设法让我的第二次尝试工作。
然后,感谢@JulianDescottes 注意到我的疏忽,我制作了这个更简洁的版本。

是工作代码。

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 中删除东西并期望它们之后能够正常工作。
至少它比当前的建议更有效,如果有人提出更好的建议,我将有义务(并且感谢)接受你的回答。

于 2013-09-06T05:53:44.047 回答