1. 理解 Vue 3 组件销毁的生命周期
在 Vue 3 的组件生命周期中,unmounted 钩子是一个关键节点,它标志着组件实例已经从 DOM 中完全移除并且所有相关资源都已释放。这个钩子函数会在以下情况下被自动调用:
- 当父组件通过
v-if条件渲染移除子组件时 - 当使用
v-for渲染的列表项被删除时 - 当调用
app.unmount()或组件实例的unmount()方法时 - 当使用路由切换导致当前组件被替换时
与 Vue 2 的 destroyed 钩子不同,Vue 3 的 unmounted 更加明确地表示组件已经从 DOM 中移除。这是一个重要的区别,因为 Vue 3 的 Composition API 引入了更细粒度的生命周期控制。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. unmounted 钩子的典型使用场景
2.1 清理定时器
最常见的用例是清理组件中创建的定时器:
javascript复制import { onMounted, onUnmounted } from 'vue'
export default {
setup() {
let timerId
onMounted(() => {
timerId = setInterval(() => {
console.log('Timer tick')
}, 1000)
})
onUnmounted(() => {
clearInterval(timerId)
console.log('Timer cleared')
})
}
}
2.2 取消事件监听器
组件中注册的全局事件监听器需要在卸载时移除:
javascript复制import { onMounted, onUnmounted } from 'vue'
export default {
setup() {
const handleResize = () => {
console.log('Window resized')
}
onMounted(() => {
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
}
}
2.3 取消网络请求
对于未完成的网络请求,可以使用 AbortController 在组件卸载时取消:
javascript复制import { onUnmounted } from 'vue'
export default {
setup() {
const controller = new AbortController()
const fetchData = async () => {
try {
const response = await fetch('/api/data', {
signal: controller.signal
})
// 处理响应
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request aborted')
}
}
}
onUnmounted(() => {
controller.abort()
})
return { fetchData }
}
}
3. 需要手动卸载的特殊场景
虽然 Vue 大多数情况下会自动处理组件卸载,但有些场景需要开发者手动干预。
3.1 动态创建的组件
通过 createApp 或 h 函数动态创建的组件需要手动卸载:
javascript复制import { createApp, h } from 'vue'
const mountDynamicComponent = (parentEl) => {
const app = createApp({
render: () => h(MyComponent)
})
const instance = app.mount(parentEl)
// 返回卸载函数
return () => {
app.unmount()
parentEl.innerHTML = ''
}
}
// 使用示例
const unmount = mountDynamicComponent(document.getElementById('container'))
// 需要时调用
unmount()
3.2 使用第三方库创建的实例
某些第三方库会创建需要手动清理的资源:
javascript复制import { onUnmounted } from 'vue'
import SomeLibrary from 'some-library'
export default {
setup() {
let libraryInstance
onMounted(() => {
libraryInstance = new SomeLibrary({
element: '#chart-container'
})
})
onUnmounted(() => {
if (libraryInstance && libraryInstance.destroy) {
libraryInstance.destroy()
}
})
}
}
3.3 使用 Teleport 的组件
Teleport 组件的内容可能存在于 DOM 的其他位置,需要特别注意:
javascript复制import { onUnmounted } from 'vue'
export default {
setup() {
const cleanup = () => {
const teleportContent = document.querySelector('.teleport-content')
if (teleportContent) {
teleportContent.remove()
}
}
onUnmounted(cleanup)
return { cleanup }
}
}
4. 常见问题与解决方案
4.1 内存泄漏检测
未正确清理资源可能导致
