移除事件监听可以说是 JavaScript 的最基础知识点之一。在页面开发中,一般会和注册事件监听配对出现,组件渲染时注册事件,组件销毁时移除事件。
最近碰到了一个小问题 - 关于如何移除第三方网站事件监听,借这个机会重新巩固了下事件机制这块知识点。
场景复现
日常写代码的一天,后边的后端大佬突然喊道:“前端小哥,有没空帮忙搞下这个,这个测评输入框不让粘贴,我搞了半小时还是不能粘贴。”
作为前端,第一直觉就是输入框对 paste
事件做了处理,先查找节点的事件。一顿操作,最后在输入框父元素找到了对应的 paste
事件:
item.addEventListener('paste', (e) => {
e.preventDefault()
})
那么问题来了,如何去移除第三方网站的一些监听事件?
我们都知道事件监听的注册有两种方式(以粘贴事件为例):
- element.onpaste = () => {}
- element.addEvenetListener('paste', handler)
对应的移除监听是:
- element.onpaste = null
- element.removeEventListener('paste', hanlder)
自己的开发项目中移除事件监听比较容易,要禁止第三方网站事件监听,不让其生效的话,我们可以尝试以下方式。
解决方案
浏览器禁止 JS
当你设置浏览器禁止使用 JavaScript 的时候,事件监听就不会在生效了
chrome 浏览器可以通过以下来设置:设置 - 隐私和安全 - 网站设置 - JavaScript
但是这种方式限制很大,你可能都无法打开测评问卷页面,现在大多网站都是单页应用,HTML 只有一个 root
节点,全靠 JS 渲染,所以不考虑。
Chrome 开发工具删除事件
打开你的开发者工具,选中对应的元素,在右侧事件监听器中可以找到当前节点的所有事件,点击“移除”即可。
我们成功地移除了事件监听,可以正常粘贴了,但是测评问卷的题目很多,不可能一个个手动去移除,还是需要继续看是否有更好的方法。
捕获阶段禁止
JavaScript 事件机制有两个阶段:捕获和冒泡,大部分情况下我们都是使用的冒泡机制,这边我们可以在 body
元素上设置一个捕获阶段监听,并阻止事件继续传递,这样 paste
事件在最开始就被禁止掉了。
document.body.addEventListener('paste', (event) => {
event.stopPropagation()
}, true) // true 设置为捕获阶段监听
执行上述代码后,输入框的粘贴功能又正常可以使用了。
使用 getEventListeners 和 removeEventListener
使用 removeEventListener
是最常规的方法,问题在于要怎么获取到监听事件函数,如果不是注册的那个监听函数,我们就无法移除事件监听。
在资料搜索中,发现 chrome 开发者工具提供了一个 api getEventListeners
,使用这个可以获取到某个元素的所有监听事件,那我们就可以使用 removeEventListener 移除掉 paste
事件。记住,这个是 Chrome 开发者工具提供的 API,在我们的 JS 代码中无法使用。
document.body.querySelectorAll('.item').forEach(item => {
item.removeEventListener('paste', getEventListeners(item)?.paste?.[0]?.listener)
})
这种方式让页面输入框恢复粘贴能力也很方便。
拓展知识
匿名函数的移除监听
我们都知道要移除监听的事件,我们的监听函数必须保证是注册时的那个,函数引用必须相同,即匿名函数无法通过 removeEventListener 移除。
但是 AbortController
API 让我们可以移除匿名函数的监听,使用方法如下:
const controller = new AbortController();
const { signal } = controller;
element.addEventListener('click', () => {
console.log('clicked');
}, { signal });
element.addEventListener('mouseover', () => {
console.log('hovered');
}, { signal });
controller.abort() // 取消监听
AbortController
API 的更多用法可以查看:AbortController AbortSignal 的使用
总结
移除事件监听是 JavaScript 中的一个基础知识点,我们要掌握它并能在实际中运用。最后除了以上方法,还有 cloneNode
方法也用来可以移除事件监听,有兴趣的同学可以试试。
如果你有更好的方法,欢迎留言讨论。
MDN 相关学习资料:事件介绍