推荐优先使用 onBeforeUnmount 而非 onUnmounted,因其触发时组件实例完整、响应式系统仍有效;定时器清理需用 ref 存储 ID 并配对清除;全局事件监听必须复用同一 handler;keep-alive 场景需结合 onDeactivated 与 onBeforeUnmount 双保险。

在组合式 API 中,onUnmounted 是组件从 DOM 完全移除后执行清理的最后机会,但它不是最安全的时机——真正推荐的是 onBeforeUnmount。因为此时组件实例仍完整可用,响应式数据、DOM 引用、this 上下文都未失效,能确保清理动作可靠执行。
为什么优先选 onBeforeUnmount 而非 onUnmounted
onUnmounted 触发时,组件已解绑:$el 为空、响应式系统停止追踪、watch 停止响应、部分 ref 可能已失活。若你在其中调用 clearInterval 或 removeEventListener,看似执行了,但若 timer ID 已被覆盖或 handler 引用丢失,实际清理可能无效。而 onBeforeUnmount 是 Vue 明确设计的“卸载前守门员”,语义清晰、时机精准、行为可控。
定时器清理:ref + onBeforeUnmount 标准写法
用 ref 存储定时器 ID,避免闭包捕获或变量覆盖问题;启动和清除逻辑严格配对,并清空引用便于调试:
- 声明
const timer = ref(null),类型建议为Ref<nodejs.timeout null></nodejs.timeout> - 在
onMounted或业务函数中赋值:timer.value = setInterval(...) - 在
onBeforeUnmount中检查并清除:if (timer.value) clearInterval(timer.value) - 清除后设为
null:timer.value = null,防止重复调用或误判
全局事件监听器清理:必须复用同一 handler 引用
window 或 document 上的事件监听器无法靠箭头函数或内联写法清理,因为每次创建都是新函数。正确做法是:
- 在 setup 顶层定义具名函数:
const handleResize = () => { ... } onMounted(() => window.addEventListener('resize', handleResize))onBeforeUnmount(() => window.removeEventListener('resize', handleResize))- 若需动态绑定多个事件,可用 Map 或数组管理 handler 和 type,统一遍历移除
兼容 keep-alive 场景的双保险策略
当组件被 <keep-alive> 包裹时,onBeforeUnmount 不会触发(组件只是缓存,未卸载)。此时应配合 onDeactivated:
- 在
onActivated中启动定时器或监听器(并加 guard 判断是否已存在) - 在
onDeactivated中清除定时器、移除事件监听 - 同时保留
onBeforeUnmount作为兜底——覆盖普通跳转与强制销毁场景


















