Js如何移除事件监听器

更新日期: 2023-03-16阅读: 180标签: 事件

在运行时清理你的代码是构建高效、可预测的应用程序,没有商量余地的部分。在JavaScript中,实现这一目标的方法之一是很好地管理事件监听器,尤其是当不再需要时移除它们。

有好几种方法可以做到这件事情,每种都有自己的一套权衡方法,使其在某些情况下更合适。我们将介绍几种最常用的策略,以及当你试图决定哪种方法最适合于任何特定时间的工作时,需要考虑的一些问题。

我们将对下面的设置进行修补--一个带有单击事件监听器的按钮:

<button id="button">Do Something</button>

<script>
document.getElementById('button').addEventListener('click', () => {
    console.log('clicked!');
});
</script>

使用getEventListeners()函数,你会看到只有一个监听器连接到该元素:


如果你需要移除该监听器,你可以用以下几个方法。


使用.removeEventListener()

这可能是最显而易见的,但也是最有可能威胁到你心智的一个。.removeEventListener()方法接收三个参数:待移除监听器的类型,监听器的回调函数,以及可选对象。

但这里有一个(潜在的)棘手的部分:这些确切的参数必须与设置监听器时使用的参数完全一致,包括内存中回调的相同引用。否则,.removeEventListener()啥也不做。

考虑到这一点,下面的示例将是完全无效的:

document.getElementById('button').addEventListener('click', () => {
    console.log('clicked!');
});

document.getElementById('button').removeEventListener('click', () => {
    console.log('clicked!');
});

尽管回调函数看起来一样,但它们不是相同的引用。解决方案是将回调函数设置为一个变量,并在.addEventListener()和.removeEventListener()中引用它。

const myCallback = () => {
  console.log('clicked!');
};

document.getElementById('button').addEventListener('click', myCallback);
document.getElementById('button').removeEventListener('click', myCallback);

或者,对于特定的用例,你也可以通过在函数本身中引用一个伪匿名函数来移除监听器:

document
  .getElementById('button')
  .addEventListener('click', function myCallback() {
    console.log('clicked!');

    this.removeEventListener('click', myCallback);
  });

尽管有其特殊性,.removeEventListener()的优势在于其目的非常明确。当你通读完代码时,对它的作用没有任何疑问。


使用.addEventListener()的once选项

如果.addEventListener()是为了一次性使用,.addEventListener()方法自带一个工具可以帮助自己清理:once选项。这和它听起来一样简单。如果设置为true,监听器会在第一次被调用后自动移除它自己:

const button = document.getElementById('button');

button.addEventListener('click', () => {
    console.log('clicked!');
}, { once: true });

// 'clicked!'
button.click();

// No more listeners!
getEventListeners(button) // {}

假设它符合你的使用情况,如果你热衷于使用匿名函数,这种方法可能是合适的,因为你的监听器只需要被调用一次。


克隆&替换节点

有时,你不知道某个节点上所有活跃的监听器,但你知道你想要摧毁它们。在这种情况下,克隆整个节点并使用克隆的替换该节点是可行的。使用.cloneNode()方法,通过.addEventListener()附加的监听器都不会被带过去,给它一个干净的环境。

让我们回到客户端JavaScript的石器时代,你会看到这是由查询到父节点,然后用一个克隆节点替换一个特定的子节点完成的:

button.parentNode.replaceChild(button.cloneNode(true), button);

但在现代浏览器中,可以使用.replaceWith()进行简化:

button.replaceWith(button.cloneNode(true));

有一件事可能会让你感到困惑,那就是内部监听器会被保留下来,这意味着一个带有onclick属性的按钮仍然会按照定义触发:

<button id="button" onclick="console.log('clicked!')">
    Do Something
</button>

总之,如果你需要用蛮力不分青红皂白地删除任何种类的监听器,这是一个值得一试的选择。然而,在缺点方面,就是它的目的不太明显。有人会说它是一个hack手段。


使用AbortController()

该方法对我来说是新的。我是在看到Caleb Porzio的这条推文时才知道的。如果你和我一样,你可能只听说过AbortController是用来取消fetch()请求的。但显然,它比这更灵活。

最近,.addEventListener()可以设置一个signal,用于终止/移除一个监听器。当相应的控制器调用.abort()时,该信号将触发监听器被删除:

const button = document.getElementById('button');
const controller = new AbortController();
const { signal } = controller;

button.addEventListener('click', () => console.log('clicked!'), { signal });

// Remove the listener!
controller.abort();

这样做最明显的好处可能是符合人体工程学。它(在我看来)是一种更清晰的移除监听器的方式,而不用处理.removeEventListener()的潜在麻烦。但也有一个更具战术性的优势:你可以使用一个信号来一次性移除多个任何类型的监听器。而且使用匿名函数也是完全可以的:

const button = document.getElementById('button');
const controller = new AbortController();
const { signal } = controller;

button.addEventListener('click', () => console.log('clicked!'), { signal });
window.addEventListener('resize', () => console.log('resized!'), { signal });
document.addEventListener('keyup', () => console.log('pressed!'), { signal });

// Remove all listeners at once:
controller.abort();

唯一让人犹豫不决的原因是浏览器支持。这是一个相对较新的功能,自2021年(v90)以来,Chrome浏览器才全面支持。因此,如果你需要支持超过有几年历史的浏览器版本,请记住这一点。


应该使用哪个

跟其他事情一样,这取决于实际使用场景:

  • 使用.removeEventListener():如果回调函数被赋值给一个变量,并且在监听器被添加的地方很容易找到时可以使用该方式。
  • 使用once选项:如果你只需要触发一次回调时,可以使用该方式。
  • 使用克隆和替换方法:如果你需要一股脑销毁多个监听器时,可以使用该方式。
  • 使用AbortController():如果你有一系列的监听器想一次性地删除,或者你只是喜欢这种语法时可以使用该方式。
原文翻译来自:https://www.macarthur.me/posts/options-for-removing-event-listeners

链接: https://www.fly63.com/article/detial/12406

js中addEventListener事件监听器参数详解

我们都知道addEventListener() 的参数约定是:useCapture是可选参数,默认值为false,目前DOM 规范做了修订:addEventListener() 的第三个参数可以是个对象值了。passive就是告诉浏览器我可不可以用stopPropagation...

js监听浏览器返回,pushState,popstate 事件,window.history对象

在WebApp或浏览器中,会有点击返回、后退、上一页等按钮实现自己的关闭页面、调整到指定页面、确认离开页面或执行一些其它操作的需求。可以使用 popstate 事件进行监听返回、后退、上一页操作。

CSS中的pointer-events属性实现点穿效果

具有层级关系的结构中,使用了pointer-events:none 属性将会使当前元素中的事件不会被捕获,从而实现了点穿的效果。而当代码示例中假如top元素具有子元素且显示指定pointer-events属性不为none的时候,top元素注册的事件将会被捕获/冒泡触发

js鼠标事件参数,获取鼠标在网页中的坐标

事件对象 event,JavaScript 将事件event作为参数传递,IE中把 event 事件对象作为全局对象 window 的一个属性,获取鼠标在网页中的坐标 = 鼠标在视窗中的坐标 + 浏览器滚动条坐标

js事件冒泡和默认事件处理(原生js、vue)

何为默认事件?比如 a 会跳转页面,submit 会提交表单等。普通js方法:e.preventDefault()函数。Vue.js方法: .prevent 是vue 的内置修饰符,调用了 event.preventDefault()阻止默认事件

js keyup、keypress和keydown事件 详解

js keyup、keypress和keydown事件都是有关于键盘的事件,当一个按键被pressed 或released在每一个现代浏览器中,都可能有三种客户端事件。

深入nodejs-核心模块Events详解(事件驱动)

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O的模型,使其轻量又高效。比如,文件操作中的fs事件流,网络编程所用到的tcp,http模块等,当你回想自己写的程序后,会发现很多操作都基于事件驱动,Events类。

纯CSS实现点击事件展现隐藏div菜单列表/元素切换

在写移动端导航的时候经常用到点击按钮出现/隐藏导航条的情况,最常见的方法当然还是前端框架直接调用,省心省力,不易出错;当然还有使用纯JS实现的小代码段。我这里整理了纯CSS实现方式,给需要的人和给自己做个笔记:实现原理利用CSS伪类:target

关于鼠标移动太快导致moseleave事件不触发的问题

我做的是一个table的编辑功能,当移入某行的时候展示编辑状态,在移出某行的时候显示的是原始状态,此时遇到一种情况,就是.当mousenter事件触发之后,由于鼠标移动得太快,同一个tr上绑定的mouseleave事件压根儿就没有执行。

Js事件传播流程

js事件传播流程主要分三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。在我们平常用的addEventListener方法中,一般只会用到两个参数,一个是需要绑定的事件,另一个是触发事件后要执行的函数

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!