Vue3中unmounted钩子在组件销毁时触发,常见场景包括:
- v-if条件变化;
- 动态组件切换;
- 路由导航;
- v-for列表更新;
- 父组件卸载;
- 手动调用unmount();
- Teleport目标移除;
- 组合式API停止响应式效果。
KeepAlive缓存的组件会触发deactivated而非unmounted。
最佳实践是在unmounted中清理定时器、事件监听等资源,避免内存泄漏。
理解这些触发条件有助于更好地管理组件生命周期。
在 Vue 3 中,unmounted 生命周期钩子会在组件实例被销毁并从 DOM 中移除后调用。
以下是会触发组件卸载(unmount)的常见情景:
1. 条件渲染导致的组件移除
vue
<template>
<ChildComponent v-if="showChild" />
</template>
<script setup>
import { ref } from 'vue'
const showChild = ref(true)
// 当 showChild 变为 false 时,ChildComponent 会被卸载
setTimeout(() => {
showChild.value = false // 触发 ChildComponent 的 unmount
}, 3000)
</script>
2. 动态组件切换
vue
<template>
<component :is="currentComponent" />
</template>
<script setup>
import { ref, shallowRef } from 'vue'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
const currentComponent = shallowRef(ComponentA)
// 切换组件时,前一个组件会被卸载
const switchComponent = () => {
currentComponent.value = ComponentB // ComponentA 会被卸载
}
</script>
3. 路由导航
javascript
// 路由导航时,离开当前路由对应的组件会被卸载
router.push('/new-route') // 当前路由组件会被卸载(如果不需要被缓存)
4. v-for 列表项变化
vue
<template>
<div v-for="item in list" :key="item.id">
<ListItem :item="item" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const list = ref([
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
])
// 移除数组元素时,对应的组件会被卸载
const removeItem = (id) => {
list.value = list.value.filter(item => item.id !== id)
}
</script>
5. 父组件被卸载
vue
<template>
<ParentComponent v-if="showParent">
<!-- 当 ParentComponent 被卸载时,所有子组件也会被卸载 -->
<ChildComponent />
</ParentComponent>
</template>
6. 手动卸载组件
vue
<template>
<div ref="container"></div>
</template>
<script setup>
import { ref, onMounted, createApp } from 'vue'
import DynamicComponent from './DynamicComponent.vue'
const container = ref(null)
let appInstance = null
onMounted(() => {
// 手动挂载组件
appInstance = createApp(DynamicComponent)
appInstance.mount(container.value)
// 手动卸载组件
setTimeout(() => {
appInstance.unmount() // 触发 unmount
container.value.innerHTML = ''
}, 5000)
})
</script>
7. 使用 <Teleport> 但目标元素被移除
vue
<template>
<Teleport :to="target">
<Modal />
</Teleport>
</template>
<script setup>
import { ref } from 'vue'
const target = ref('body')
// 如果目标元素被从 DOM 中移除,通过 Teleport 传送的组件也会被卸载
</script>
8. 在组合式 API 中手动停止响应式效果
vue
<script setup>
import { onUnmounted } from 'vue'
// 当组件被卸载时,onUnmounted 钩子会被调用
onUnmounted(() => {
console.log('组件已卸载')
// 清理工作,如清除定时器、取消事件监听等
})
</script>
特殊情况:组件不会被卸载
使用 <KeepAlive> 缓存组件
vue
<template>
<KeepAlive>
<ComponentA v-if="showA" />
<ComponentB v-else />
</KeepAlive>
</template>
-
组件切换时不会触发
unmounted,而是触发deactivated -
从缓存中移除时才会触发
unmounted
使用 <Suspense> 的异步组件
异步组件的加载和卸载有特殊处理,但最终卸载时仍会触发 unmounted。
最佳实践
在 unmounted 或 onUnmounted 中:
-
清理定时器
-
取消事件监听器
-
清理第三方库实例
-
取消网络请求
-
清理全局状态监听
vue
<script setup>
import { onUnmounted } from 'vue'
let intervalId
onMounted(() => {
intervalId = setInterval(() => {
console.log('定时执行')
}, 1000)
})
onUnmounted(() => {
clearInterval(intervalId) // 清理定时器
})
</script>
理解这些触发情景有助于更好地管理组件生命周期和资源清理。