注册和销毁必须严格配对,确保 removeEventListener 使用完全相同的函数引用、事件名和 options;统一在 beforeUnmount(Vue 3)或 beforeDestroy(Vue 2)中集中清理;优先用 watchEffect + onInvalidate 管理响应式副作用;第三方库需显式调用 dispose/destroy/off 方法。

核心是“注册和销毁必须严格配对”,尤其要避开匿名函数、参数不一致等常见坑。
确保 removeEventListener 能真正生效
用 addEventListener 添加的监听器,必须用完全相同的函数引用、事件名和 options(比如 { capture: true })才能被 removeEventListener 移除。
- 不要在
mounted里传匿名函数:window.addEventListener('scroll', () => {...})→ 后续无法移除 - 正确做法:把处理函数声明为组件方法或用
ref保存引用 - 如果用了
capture: true或{ passive: false },remove时也要带一模一样的 options
统一在 beforeUnmount 中集中清理(Vue 3)或 beforeDestroy(Vue 2)
这是最稳妥的清理时机,避免依赖组件是否还存活。所有手动绑定的全局或 DOM 事件都应在此处解绑。
- 例如监听窗口大小:
mounted中绑定resize,beforeUnmount中调用window.removeEventListener('resize', handler) - 同一组件若绑定多个事件(如
scroll、keydown),建议用数组统一管理,销毁时遍历清除 - 避免在
unmounted或destroyed中清理——此时组件实例可能已部分失活,this 方法或 data 可能不可靠
优先使用 Composition API 的 watchEffect + onInvalidate
对于响应式依赖的副作用(比如监听 ref 变化后触发 DOM 操作),用 watchEffect 更安全,它内置自动清理机制。
立即学习“前端免费学习笔记(深入)”;
-
watchEffect内部回调执行前,会自动清除上一次的副作用 - 需要更精细控制时,可用
onInvalidate注册清理函数,比如取消未完成的 fetch 请求 - 比手写
addEventListener+ 生命周期钩子组合更简洁、不易出错
警惕第三方库的事件残留
ECharts、Mapbox、Swiper 等库内部常自行绑定事件或创建定时器,它们不一定随组件卸载自动释放。
- 查阅文档,确认是否有
.dispose()、.destroy()或.off()方法 - 在
beforeUnmount中显式调用释放方法,例如chartInstance.dispose() - 避免直接操作库实例的 DOM 容器并重复初始化,容易累积监听器


















