如何移除事件监听器

如何,移除,事件,监听器 · 浏览次数 : 1520

小编点评

## Summary of the Article This article dives into various methods for cleaning up event listeners in JavaScript, specifically focusing on managing click event listeners. It explores the pros and cons of each approach and provides recommendations for choosing the most suitable method for your specific needs. **Key Concepts:** * **Event Listeners:** Event listeners are functions that are called when a specific event occurs on an element. * **Event Listeners and Event Listeners at Once:** Using `addEventListener()` allows you to attach one listener to multiple events. * **Removing Event Listeners:** `removeEventListener()` allows you to detach a listener once it's no longer needed. * **Event Listeners and `once` Option:** Setting the `once` option to `true` automatically removes the listener after it's called. * **Cloning and Replacing Node:** This method allows you to create a copy of a node and replace the original node with it, effectively removing the listener. * **AbortController():** This is a modern approach for managing event listeners that allows you to easily remove them. **Recommendations:** * Use `removeEventListener()` when you need to remove a listener after it's no longer needed. * Use `once` if you only need to trigger the callback function once. * Use `cloneNode()` and `addEventListener` to remove multiple listeners at once. * Consider using `AbortController` for flexibility and support across different browsers. **Choosing the Right Method:** * Consider the specific needs of your application and the events you need to handle. * If you need to remove a listener after it's triggered, `removeEventListener` is a simple choice. * Use `once` when you only need to trigger the callback function once. * Use `cloneNode` and `addEventListener` for situations where you need to remove multiple listeners. * Use `AbortController` for scenarios where you have a series of listeners that need to be removed at once. **Additional Notes:** * Remember to handle potential issues when removing event listeners. * Explore the `AbortController` documentation for more advanced use cases.

正文

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

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

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

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

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

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

getEventListeners.png

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

使用.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():如果你有一系列的监听器想一次性地删除,或者你只是喜欢这种语法时可以使用该方式。

以上就是本文的全部内容,如果对你有所帮助,欢迎点赞、收藏、转发~

与如何移除事件监听器相似的内容:

如何移除事件监听器

在运行时清理你的代码是构建高效、可预测的应用程序,没有商量余地的部分。在JavaScript中,实现这一目标的方法之一是很好地管理事件监听器,尤其是当不再需要时移除它们。 有好几种方法可以做到这件事情,每种都有自己的一套权衡方法,使其在某些情况下更合适。我们将介绍几种最常用的策略,以及当你试图决定哪

轻应用技术是什么?如何进行落地

移动互联网风起云涌的数十年来,App 似乎成为了企业与用户打交道最“理所当然”的形式,更年轻一代的用户甚至可能认为 App 就是一个“与生俱来”的事物,但随着移动互联网发展的高峰离去,App 面临着发展的困境和疲态。最明显的感知就是这几年以微信、支付宝、抖音等“超级 App”们大行其道,占据了用户超过80%的手机使用时间,而其他大多数 App 则成为了用户手机的内存侵夺者。

setTimeout(fn, 0) // it works - JavaScript 事件循环 动画演示

在前端代码中很经常看到使用 setTimeout(fn, 0),如下面代码所示,乍一看很多余,但是移除了可能会出现一些奇奇怪怪的问题。要解释这个就需要理解 事件循环(Event Loop),下面会通过一些例子和动画来辅助理解事件循环 setTimeout(() => { // 调用一些方法 }, 0

ASP.NET Core如何禁用模型验证(或者从模型状态中移除某些属性)?

这是一篇4年前的文章:【经验分享】在ASP.NET Core中,如果禁用某个请求的模型验证? 事隔多年,又有网友问到这个问题。我就来重新整理一下,顺便扩展一下之前的解决办法。 这是一个来自网友【David】的提问。在 AppBoxCore 项目的新增用户页面,新增一个上传按钮:

FreeRTOS简单内核实现7 阻塞链表

0、思考与回答 0.1、思考一 如何处理进入阻塞状态的任务? 为了让 RTOS 支持多优先级,我们创建了多个就绪链表(数组形式),用每一个就绪链表表示一个优先级,对于阻塞状态的任务显然要从就绪链表中移除,但是阻塞状态的任务并不是永久阻塞了,等待一段时间后应该从阻塞状态恢复,所以我们需要创建一个阻塞链

驱动开发:内核无痕隐藏自身分析

在笔者前面有一篇文章`《驱动开发:断链隐藏驱动程序自身》`通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的驱动隐藏的,总体来说作者的思路是最终寻找到`MiProcessLoaderEntry`的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。

如何在移动端数据可视化大屏实现分析?

本文由葡萄城技术团队于博客园原创并首发转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 项目想做数据可视化,想同时在PC端、手机端查看数据怎么办?业务主要关心的数据包括:销售数据、业绩达成、同比、环比,各产品销售情况及潜客商机、未来收入预测等数据,最好附加人

[转帖]如何使用 sed 命令删除文件中的行

https://zhuanlan.zhihu.com/p/80212245 sed 命令是 Linux 中的重要命令之一,在文件处理方面有着重要作用。可用于删除或移动与给定模式匹配的特定行。-- Magesh Maruthamuthu(作者) Sed 代表 流编辑器(Stream Editor),常

如何使用Node.js、TypeScript和Express实现RESTful API服务

Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。Express是一个保持最小规模的灵活的 Node.js Web应用程序开发框架,为Web和移动应用程序提供一组强大的功能。使用Node

教你如何轻松搞定云上打印管理

摘要:加快自主创新,满足数字化用户多场景文印需求。 本文分享自华为云社区《有了司印云打印,云上打印管理轻松搞定!》,作者:云商店 。 作为与职场和个人办公息息相关的工作场景,打印长期以来都是办公业务的核心应用和基本能力之一,即使在移动办公、云办公的时代仍然如此。 当前,市面上的打印机品牌型号差异大,