如何阻止document绑定的keydown事件监听器触发重复事件?
问题原因
你当前绑定在document全局对象上的事件监听器不会随组件销毁自动清除,导航离开页面时旧监听器一直挂载,每次重新进入页面mounted执行时又新增一个监听器,就会出现事件多次触发的问题。你之前的移除逻辑未生效,大概率是添加和移除监听器时传入的函数引用不一致,导致旧监听器没有被正确删掉。
解决方案
1. 固定监听器函数引用
提前将绑定好组件实例this的监听器函数存起来,不要每次调用bind生成新的函数引用,保证移除和添加的是同一个函数。
2. 组件销毁时主动清理全局监听器
在组件卸载生命周期中手动移除绑定在document上的监听器,从根源避免残留。
完整代码示例(Vue2为例,Vue3替换beforeDestroy为beforeUnmount即可)
export default { data() { return { // 其他现有数据... boundKeydownListener: null // 存储固定的监听器引用 } }, mounted() { this.setupInputListener(); }, // 组件销毁前清理全局监听器 beforeDestroy() { if (this.boundKeydownListener) { document.removeEventListener('keydown', this.boundKeydownListener); } }, methods: { // 补充event形参,避免直接从全局window拿事件对象 keydownListener(event) { const action = handleKeyDown(event.key); if (action) { this.SEND_INPUT({ gameId: this.gameId, action: action }); } }, setupInputListener() { // 只绑定一次this,生成固定引用 this.boundKeydownListener = this.keydownListener.bind(this); // 先移除已有监听器 document.removeEventListener('keydown', this.boundKeydownListener); document.addEventListener('keydown', this.boundKeydownListener); } } }
注意事项
- 不要直接在
addEventListener参数里写this.keydownListener.bind(this),每次bind调用都会返回全新的函数实例,后续removeEventListener传入的引用和添加时不一致,会导致移除失败。 - 所有绑定在
window、document这类全局对象上的事件、定时器等副作用,都需要在组件销毁时手动清理,否则会出现内存泄漏、事件重复触发等问题。
内容的提问来源于stack exchange,提问作者hipsterstomper69
相关产品推荐
相关产品推荐

