【问题标题】:How to remove all listeners in an element? [duplicate]如何删除元素中的所有侦听器? [复制]
【发布时间】:2012-03-04 08:12:57
【问题描述】:

我有一个按钮,我在上面添加了一些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>

我可以通过以下方式删除它们:

document.getElementById("btn").removeEventListener("click",funcA);

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

【问题讨论】:

  • 因尝试通过不使用框架/库来胜任编码而被投票赞成。 :-)
  • @user 令人印象深刻,您实际上发现了一个比这个旧问题更古老的问题,这里的答案仍然提到 jQuery 1.7。不敢相信自从我问这个问题以来已经过去了多少时间。

标签: javascript dom-events addeventlistener


【解决方案1】:

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

var old_element = document.getElementById("btn");
var new_element = old_element.cloneNode(true);
old_element.parentNode.replaceChild(new_element, old_element);

请小心,因为这也会清除相关节点的所有子元素上的事件侦听器,因此如果您想保留它,您必须一次明确地移除一个侦听器。

【讨论】:

  • @Derek:克隆一个节点和整个子树是个坏主意。它比使用node.removeEventListener 从节点中删除所有EventListeners 慢很多。此外,您将获得内存泄漏(节点 + 子树),当然所有 EventListeners 都已从子树中删除。如果你在document.body 上使用你的函数,你会炸毁一切。
  • @Saxoier,感谢您的提醒,但我在此页面的 body 上进行了测试,它就像一个魅力。也许我正在使用快速浏览器(谷歌浏览器)。
  • @Saxoier 当然克隆节点比仅仅删除监听器要慢,但是在大多数功能场景中,速度差异是不可辨别的(除非你对大量的页面节点都这样做一气呵成)。至于内存泄漏,这将取决于浏览器......所有现代浏览器都应该很好地处理垃圾收集,不会遇到问题(尽管如果节点包含嵌入式对象,我可以想象可能发生这种情况的场景)。您是否想到了特定的记录内存泄漏?
  • 对于那些讨厌神秘的布尔参数的人来说,cloneNode(true) 意味着克隆节点,包括子节点。文档:developer.mozilla.org/en-US/docs/Web/API/Node.cloneNode
  • @BenD 有趣的是,有 3 个反对票,但没有其他答案……对于那些反对票的人来说,这是一场相当弱的表演!
【解决方案2】:

如果你使用 jquery 事件,这可以在一行中完成:

对于 jQuery 事件 (.on()):

$("#myEl").off()

对于原生 javascript 事件 (.addEventListener()):

$('#myEl').replaceWith($('#myEl').clone());

这是一个例子:

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

【讨论】:

  • 太长了,在 jQuery 中你应该这样做 $("#myEl").unbind();.off() (1.7+) 来删除所有的监听器。
  • off()unbind() 是否只删除那些通过 jQuery 附加的监听器?
  • 不知道为什么unbindoff 不起作用。但是$('#myEl').replaceWith($('#myEl').clone()); 效果很好!
  • @davide @Duke 实际上 off()unbind() 不适用于使用原生 javascript addEventListener 注册的侦听器,根据 jquery 文档。
  • 看起来这只会删除使用 jQuery 创建的事件,因此不是一个完整的解决方案。
【解决方案3】:

这是一个同样基于 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);
  }
}

移除一个元素上的事件监听器:

recreateNode(document.getElementById("btn"));

移除一个元素及其所有子元素上的事件监听器:

recreateNode(document.getElementById("list"), true);

如果您需要保留对象本身,因此不能使用cloneNode,那么您必须包装addEventListener 函数并自己跟踪侦听器列表,例如this answer

【讨论】:

  • @Max:我很欣赏你的编辑建议,但我认为在这种情况下将这段代码重新制作成 ES2015 是不合理的,那时代码不会得到广泛支持。
  • 删除所有可以使用的子级监听:element.innerHTML += '';
  • @NazarVynnytskyi 确实,这是一个快速但有效的解决方案!
猜你喜欢
  • 1970-01-01
  • 2012-09-10
  • 2014-02-27
  • 2012-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-10
相关资源
最近更新 更多