必须手动移除由 addeventlistener 添加且目标对象生命周期长于组件的监听器,如 window/document、第三方 dom 容器及强引用的组件内元素;v-on 绑定的无需处理。

Vue 组件销毁时,手动添加的 EventListener 必须显式移除,否则会持续持有组件引用,引发内存泄漏、重复触发、逻辑错乱等问题。这不是可选项,而是资源管理的基本契约。
哪些监听器必须手动移除?
核心判断标准:是否由你主动调用 addEventListener 添加,且目标对象在组件卸载后依然存在。
- window / document / 全局对象:必须移除。它们生命周期远长于组件,不清理就会永久驻留;
- 第三方 DOM 容器(如地图 div、canvas、插件生成的元素):必须移除。这些节点不受 Vue 管控,不会随组件自动销毁;
-
当前组件内创建并强引用的 DOM 元素(例如存进
ref或 data 的元素):需移除。即使 DOM 被 Vue 卸载,若 JS 仍持有该元素引用,其监听器也不会自动释放; - v-on 绑定的事件(@click、@input 等):无需手动处理。Vue 内部已自动管理,组件卸载时一并解绑。
移除的关键前提:函数引用必须一致
removeEventListener 不认函数“内容”,只认函数“身份”。每次写 () => {} 或 function() {} 都是新对象,无法匹配。
- ✅ 正确:定义为 methods 方法、setup 中的具名函数,或用
useCallback/ref缓存稳定引用; - ❌ 错误:在
mounted中写el.addEventListener('click', () => this.do()),卸载时调用removeEventListener无效; - ⚠️ 注意:
useCapture参数也要完全一致,否则同样匹配失败。
在哪个时机移除?
不是“组件看不见了”才清,而是在它彻底失去上下文前——此时 this、ref、state 仍可安全访问。
-
Vue 2:用
beforeDestroy(destroyed已晚,this 可能为 null); -
Vue 3 Options API:同 Vue 2,用
beforeUnmount; -
Vue 3 Composition API:用
onBeforeUnmount(onUnmounted中 DOM 可能已不存在,无法访问绑定的元素); -
React 类比:等价于
useEffect清除函数执行时刻。
常见遗漏项要一并清理
事件监听器常和其他副作用共存,漏清一个就可能连带泄漏。
-
定时器:用
ref存setTimeout/setIntervalID,卸载时调用clearTimeout/clearInterval; -
自定义事件总线(如 mitt、EventBus):用
$off或off()移除对应 handler,避免用removeAllListeners()误伤其他组件; -
WebSocket / SSE 连接:调用
.close(),并设状态标记防止重连; -
第三方 SDK 实例(ECharts、Leaflet、Three.js 场景等):查阅文档,调用
.dispose()、.destroy()或.remove()。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











