vue 3 中需手动解绑的只有两类:一是 setup 或 onmounted 中用 $on 动态注册的自定义事件监听器,二是原生 dom 事件监听器;其余如模板中 @event 绑定、子组件 $emit、.once 修饰符等均由 vue 自动管理。

Vue 3 中自定义事件本身不会自动解绑,但只要不是手动用 $on 动态绑定的,通常无需主动解绑——因为组件卸载时,其内部所有自定义事件监听(比如父组件通过 @event="handler" 绑定的)会随组件实例自然失效。真正需要你主动干预的,是那些**手动调用 $on 动态注册的监听器**,以及**原生 DOM 事件监听器**。
哪些自定义事件要手动解绑?
只有以下两类场景才需显式调用 $off:
- 在
setup或onMounted中用component.$on('xxx', handler)显式监听了子组件发射的自定义事件(例如通过ref拿到子组件实例后绑定) - 在自定义指令或
mounted阶段用addEventListener绑定了原生 DOM 事件(如window.resize、document.click)
正确解绑动态 $on 监听器
若你在父组件中这样手动监听子组件事件:
const childRef = ref()
onMounted(() => {
childRef.value.$on('update', handleUpdate)
})
就必须在卸载前对应解绑:
onBeforeUnmount(() => {
childRef.value.$off('update', handleUpdate)
})
注意:必须传入相同的事件名和同一函数引用,否则 $off 不生效;不能传匿名函数或箭头函数(会丢失引用)。
原生事件监听必须配对移除
这是最常被忽略、也最容易导致内存泄漏的地方:
- 在
onMounted中用addEventListener添加监听 → 必须在onBeforeUnmount中用removeEventListener移除 - 两个函数参数必须完全一致:事件类型、处理函数(必须是同一个函数引用)、选项(如
{ once: true }或{ capture: true }) - 推荐把处理函数声明为具名函数或
const常量,避免匿名函数
不需要解绑的情况
这些 Vue 自动管理,你不用操心:
- 模板中写的
@custom-event="handler"(本质是编译时绑定,与组件生命周期绑定) - 子组件内部用
this.$emit('xxx')触发的事件(只是通知,不产生监听器) - 使用
.once修饰符的事件(触发一次后自动解绑)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










