为了优化性能,我们常见的做法之一、就是当我们不再需要的某些事件的时候,移除不必要的事件监听。
那么除了removeEventListener,你还能想到别的方式么?
下面介绍其他几种方式、让我们在合适的时候,使用合适的方法
通常我们这样绑定一个事件
<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!');
});
虽然两个函数看上去一样,但是因为不是一个引用,所以不能移除掉,可以将回调函数设置为一个变量,如下
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);
});
二、addEventListener() 搭配 once
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()连接的监听函数
button.parentNode.replaceChild(button.cloneNode(true), button);
在现代浏览器中,可以使用replaceWith()来简化
button.replaceWith(button.cloneNode(true));
但是通过'onclick'绑定的事件,通过克隆仍然是存在。
<button id="button" onclick="console.log('clicked!')">
Do Something
</button>
总之,你想暴力的移除所有的事件监听,这个是一个不错的方法。
四、AbortController()
之前只是听说过,AbortController用于取消fetch()请求,但是显然它更加灵活。
最近,.addEventListener()可以搭配 signal 强制终止事件监听
来自MDN:AbortController 接口的只读属性 signal 返回一个 AbortSignal 实例对象,该对象可以根据需要处理 DOM 请求通信,既可以建立通信,也可以终止通信。
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() 的情况下移除事件,还有一个更加高效的方式是 使用一个 signal 移除多个事件监听,匿名函数也可以。
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
- 如果只触发一次回调,可以使用 addEventListener() 搭配 once
- 如果无差别的删除多个事件,可以使用 克隆 或 替 换节点
- 如果有一系列要立即强制删除的事件监听,或者只是想尝试一下新语法,可以试试AbortController()。