Vue组件卸载是分阶段资源回收过程:先递归卸载子vnode,再触发beforeUnmount/unmounted钩子,最后移除DOM;onUnmounted是最安全清理入口,需显式销毁第三方库、清除定时器、解绑事件、终止请求;effectScope和watchEffect的onInvalidate可自动化管理副作用。

Vue.js 组件卸载不是简单地删掉 DOM,而是渲染管线中一个有明确顺序、分阶段执行的资源回收过程。它依赖 vnode 的 diff 和卸载流程提供清理时机,真正释放资源靠的是开发者在正确位置写清理逻辑。
卸载流程:vnode 递归卸载 → 钩子触发 → DOM 移除
当组件因 v-if 为 false、路由切换或手动调用 unmount() 而退出时,Vue 渲染器启动卸载流程:
- 先递归卸载所有子 vnode,确保嵌套组件、动态内容、过渡节点等全部完成退出
- 再执行指令的
beforeUnmount和unmounted钩子,让自定义指令(如拖拽、焦点管理)有机会解绑事件、清除定时器 - 最后调用平台层移除操作(
hostRemove(el)),清空vnode.el和vnode.component引用,真实 DOM 节点才被移除
onUnmounted 是最常用也最安全的清理入口
这个钩子在 vnode 从树中移出、DOM 尚未被移除时执行,此时组件实例仍完整可用,能安全访问 ref、调用 unwatch、关闭第三方实例:
- 清除定时器:
clearInterval/clearTimeout,避免回调在已销毁组件中执行 - 解绑全局事件:
window.removeEventListener,注意传入的回调必须是同一引用(不能用匿名函数) - 取消请求:配合
AbortController或 Axios 的 cancel token 主动终止 pending 请求 - 注销共享状态:例如从
shadcn-vue的allItems.value.delete(id)中移除当前实例
effectScope 提供自动化的副作用管理能力
当逻辑封装成可复用组合式函数(如 usePolling、useWebSocket)时,手动维护 onUnmounted 容易遗漏。这时 effectScope 更可靠:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
立即学习“前端免费学习笔记(深入)”;
- 用
scope.run(() => { ... })包裹所有响应式操作(watch、setTimeout、addEventListener) - 所有注册的副作用会被自动收集进该作用域
- 在
onUnmounted中调用scope.stop(),即可一键停止并清理全部关联资源
第三方库必须显式销毁,不能依赖自动回收
像 ECharts、Mapbox、Chart.js、IntersectionObserver 这类库,内部持有 DOM、Canvas、WebGL 或长连接,仅靠 v-if 移除 DOM 并不能释放它们:
-
Chart.js:调用chart.destroy() -
Mapbox GL JS:调用map.remove()或监听remove事件 -
IntersectionObserver:调用observer.disconnect() - 销毁前先断开数据流(如取消请求、关闭 EventSource),再调用销毁方法
watchEffect 的 onInvalidate 适合细粒度清理
对于防抖、轮询、pending 请求这类“可能被中断”的副作用,watchEffect 内置的 onInvalidate 机制比手动管理更精准:
- 每次新副作用运行前,上一次的
onInvalidate回调会自动执行(包括组件卸载时) - 示例:
watchEffect(onInvalidate => { const timer = setTimeout(...); onInvalidate(() => clearTimeout(timer)); }) - 适合清理待执行的定时器、取消未完成的 fetch、重置第三方库状态

















