如何删除元素中的所有侦听器?

Der*_*會功夫 187 javascript javascript-events addeventlistener

我有一个按钮,我添加了一些eventlistners:

document.getElementById("btn").addEventListener("click", funcA, false);
document.getElementById("btn").addEventListener("click", funcB, false);
document.getElementById("btn").addEventListener("click", funcC, false);
document.getElementById("btn").addEventListener("blur" , funcD, false);
document.getElementById("btn").addEventListener("focus", funcE, false);

<button id="btn">button</button>
Run Code Online (Sandbox Code Playgroud)

我可以删除它们:

document.getElementById("btn").removeEventListener("click",funcA);
Run Code Online (Sandbox Code Playgroud)

如果我想要立即删除所有侦听器,或者我没有函数reference(funcA),该怎么办?有没有办法做到这一点,或者我必须逐个删除它们?

Ben*_*n D 167

我认为最快的方法是克隆节点,这将删除所有事件侦听器:

var old_element = document.getElementById("btn");
var new_element = old_element.cloneNode(true);
old_element.parentNode.replaceChild(new_element, old_element);
Run Code Online (Sandbox Code Playgroud)

请注意,因为这也会清除所讨论节点的所有子元素上的事件侦听器,因此如果您想要保留它,则必须一次一个地显式删除侦听器.

  • @Derek:克隆节点和整个子树是个坏主意.它比使用`node.removeEventListener`从节点中删除所有`EventListener'慢得多**.此外,您将获得内存泄漏(节点+子树),当然所有`EventListener'都从子树中删除.如果你在`document.body`上使用你的功能,那么你将会爆炸一切. (35认同)
  • 对于那些讨厌神秘布尔参数的人来说,cloneNode(true)意味着克隆包含子节点的节点.文档:https://developer.mozilla.org/en-US/docs/Web/API/Node.cloneNode (7认同)
  • @Saxoier肯定克隆节点比删除侦听器慢,但在大多数功能场景中,速度差异是不可辨别的(除非你一次性对大量的页面节点这样做).至于内存泄漏,这将取决于浏览器...所有现代浏览器都应该很好地处理垃圾收集,以免遇到问题(尽管如果节点包含嵌入对象,我可以想象这可能发生的情况).您是否记得特定的记录内存泄漏? (4认同)
  • @BenD有趣的是有3张下来的选票,但没有其他答案...这是一个非常弱的表现,那些下来的选民! (2认同)

Duk*_*uke 37

如果您不反对jquery,可以在一行中完成:

jQuery 1.7+

$("#myEl").off()
Run Code Online (Sandbox Code Playgroud)

jQuery <1.7

$('#myEl').replaceWith($('#myEl').clone());
Run Code Online (Sandbox Code Playgroud)

这是一个例子:

http://jsfiddle.net/LkfLezgd/3/

  • @davide @Duke确实`off()`和`unbind()`对于使用本机javascript`addEventListener`注册的侦听器不起作用,如jquery docs所示. (20认同)
  • `off()`或`unbind()`只删除那些通过jQuery附加的监听器? (17认同)
  • 不知道为什么`unbind`和`off`不起作用.然而`$('#myEl').replaceWith($('#myEl').clone());`效果很好! (3认同)
  • 看起来这只会删除使用jQuery创建的事件,因此不是一个完整的解决方案. (3认同)
  • 这太长了,在 jQuery 中,您应该执行 `$("#myEl").unbind();` 或 `.off()` (1.7+) 来删除所有侦听器。 (2认同)

use*_*ser 11

这是一个也基于的函数cloneNode,但是只能克隆父节点并移动所有子节点(以保留它们的事件侦听器):

function recreateNode(el, withChildren) {
  if (withChildren) {
    el.parentNode.replaceChild(el.cloneNode(true), el);
  }
  else {
    var newEl = el.cloneNode(false);
    while (el.hasChildNodes()) newEl.appendChild(el.firstChild);
    el.parentNode.replaceChild(newEl, el);
  }
}
Run Code Online (Sandbox Code Playgroud)

删除一个元素上的事件侦听器:

recreateNode(document.getElementById("btn"));
Run Code Online (Sandbox Code Playgroud)

删除元素及其所有子元素上的事件侦听器:

recreateNode(document.getElementById("list"), true);
Run Code Online (Sandbox Code Playgroud)

如果你需要保留对象本身而不能使用cloneNode,那么你必须自己包装addEventListener函数并跟踪监听器列表,就像在这个答案中一样.

  • 删除您可以使用的所有子级监听: element.innerHTML += ''; (3认同)