乐趣区

关于javascript:如何移除事件监听器

在运行时清理你的代码是构建高效、可预测的应用程序,没有商量余地的局部。在 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():如果你有一系列的监听器想一次性地删除,或者你只是喜爱这种语法时能够应用该形式。

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

退出移动版