生命周期流程图
开始
│
├─ 初始化阶段
│ │
│ ├─ setup() 🔵 Composition API入口
│ │
│ └─ beforeCreate() 🟡 Options API(组合式API中不存在)
│ │
│ └─ created() 🟡 Options API(组合式API中不存在)
│
├─ 挂载阶段
│ │
│ ├─ onBeforeMount() ⚪ 挂载前
│ │
│ ├─ 编译模板
│ │
│ ├─ 创建虚拟DOM
│ │
│ ├─ 挂载到真实DOM
│ │
│ └─ onMounted() ✅ 挂载完成
│
├─ 更新阶段
│ │
│ ├─ onBeforeUpdate() 🔄 更新前
│ │
│ ├─ 重新渲染虚拟DOM
│ │
│ ├─ 打补丁(DOM更新)
│ │
│ └─ onUpdated() ✅ 更新完成
│
├─ 卸载阶段
│ │
│ ├─ onBeforeUnmount() ⚠️ 卸载前
│ │
│ ├─ 移除DOM元素
│ │
│ └─ onUnmounted() ❌ 卸载完成
│
└─ 缓存组件特殊阶段(keep-alive)
│
├─ onActivated() 🔄 激活时
│
└─ onDeactivated() 💤 停用时
一、生命周期钩子对照表
| Options API | Composition API | 调用时机 | 常用场景 |
|---|---|---|---|
beforeCreate |
❌ 无对应 | 实例初始化后,数据观测/事件配置前 | 极少使用 |
created |
❌ 无对应 | 实例创建完成,数据观测/事件配置完成 | Options API 中用于数据初始化 |
beforeMount |
onBeforeMount |
挂载开始之前 | 服务端渲染中获取数据 |
mounted |
onMounted |
挂载完成后 | DOM操作、数据请求、定时器、事件监听 |
beforeUpdate |
onBeforeUpdate |
数据更新,DOM 重新渲染前 | 获取更新前的DOM状态 |
updated |
onUpdated |
数据更新,DOM 重新渲染后 | DOM依赖操作、第三方库初始化 |
beforeDestroy (Vue 2) |
onBeforeUnmount |
实例销毁前 | 清理定时器、取消订阅、解绑事件 |
destroyed (Vue 2) |
onUnmounted |
实例销毁后 | 极少使用 |
activated |
onActivated |
keep-alive 组件激活时 | 恢复数据、重新请求 |
deactivated |
onDeactivated |
keep-alive 组件停用时 | 暂停定时器、保存状态 |
二、组合式API用法详解
2.1 基本使用
javascript
<script setup>
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onActivated,
onDeactivated,
ref
} from 'vue'
const count = ref(0)
// 1. 挂载阶段
onBeforeMount(() => {
console.log('1. onBeforeMount - 挂载前')
// 此时组件尚未挂载到DOM
console.log('DOM元素:', document.querySelector('.app')) // null
})
onMounted(() => {
console.log('2. onMounted - 挂载完成')
// ✅ 最佳实践:
// - DOM操作(获取元素、初始化图表等)
// - 发起数据请求
// - 设置定时器
// - 添加事件监听
const el = document.querySelector('.app')
console.log('DOM元素:', el) // 真实DOM
// 示例:初始化图表
// initChart()
// 示例:请求数据
// fetchData()
// 示例:开始定时器
// timer = setInterval(() => {}, 1000)
// 示例:监听窗口大小变化
// window.addEventListener('resize', handleResize)
})
// 2. 更新阶段
onBeforeUpdate(() => {
console.log('3. onBeforeUpdate - 更新前')
console.log('count更新前的值:', count.value)
// 可以获取更新前的DOM状态
const el = document.querySelector('.count')
console.log('更新前文本:', el?.textContent)
})
onUpdated(() => {
console.log('4. onUpdated - 更新完成')
console.log('count更新后的值:', count.value)
// ⚠️ 注意事项:
// 1. 避免在updated中修改响应式数据,可能导致无限循环
// 2. 确保DOM更新已经完成
// ✅ 适用场景:
// - 第三方库需要基于DOM初始化
// - 获取更新后的DOM尺寸
// 示例:重新初始化第三方库
// if (chartInstance) {
// chartInstance.dispose()
// initChart()
// }
})
// 3. 卸载阶段
onBeforeUnmount(() => {
console.log('5. onBeforeUnmount - 卸载前')
// ✅ 必须清理!防止内存泄漏
// - 清除定时器
// - 取消事件监听
// - 清理全局状态
// - 取消网络请求
// 示例:清理定时器
// if (timer) clearInterval(timer)
// 示例:移除事件监听
// window.removeEventListener('resize', handleResize)
// 示例:取消未完成的请求
// if (currentRequest) currentRequest.abort()
})
onUnmounted(() => {
console.log('6. onUnmounted - 卸载完成')
// 此时组件实例已完全销毁
// 可用于记录日志或清理全局资源
})
// 4. keep-alive 相关
onActivated(() => {
console.log('激活组件')
// 组件从缓存中激活时调用
// 恢复数据、重新开始定时器等
// 示例:恢复定时器
// if (timerPaused) {
// startTimer()
// timerPaused = false
// }
})
onDeactivated(() => {
console.log('停用组件')
// 组件被缓存时调用
// 暂停定时器、保存状态等
// 示例:暂停定时器
// pauseTimer()
// timerPaused = true
})
</script>
<template>
<div class="app">
<div class="count">Count: {{ count }}</div>
<button @click="count++">增加</button>
</div>
</template>
2.2 执行顺序示例
javascript
<!-- ParentComponent.vue -->
<script setup>
import ChildComponent from './ChildComponent.vue'
import { onMounted, ref } from 'vue'
const showChild = ref(true)
onMounted(() => {
console.log('父组件 mounted')
})
</script>
<template>
<div>
<button @click="showChild = !showChild">切换子组件</button>
<ChildComponent v-if="showChild" />
</div>
</template>
<!-- ChildComponent.vue -->
<script setup>
import { onMounted, onUnmounted } from 'vue'
onMounted(() => {
console.log('子组件 mounted')
})
onUnmounted(() => {
console.log('子组件 unmounted')
})
</script>
<!-- 执行顺序:
1. 父组件 setup
2. 子组件 setup
3. 子组件 onMounted
4. 父组件 onMounted
5. 切换时:子组件 onUnmounted
-->
三、Options API 生命周期
javascript
<script>
export default {
data() {
return {
count: 0
}
},
// 1. 初始化阶段(在 Composition API 中被 setup 替代)
beforeCreate() {
console.log('beforeCreate')
// 此时:data未初始化,methods未定义
// console.log(this.count) // undefined
},
created() {
console.log('created')
// ✅ 可以访问:data、methods、computed
// ❌ 不能访问:DOM($el)
// 用途:数据初始化、API请求(服务端渲染)
console.log(this.count) // 0
console.log(this.$el) // undefined
},
// 2. 挂载阶段
beforeMount() {
console.log('beforeMount')
// 模板编译完成,但尚未挂载到DOM
console.log(this.$el) // undefined 或 编译前的模板
},
mounted() {
console.log('mounted')
// 与组合式API的onMounted用途相同
this.$nextTick(() => {
// 确保DOM已完全更新
})
},
// 3. 更新阶段
beforeUpdate() {
console.log('beforeUpdate')
},
updated() {
console.log('updated')
// 小心:不要在这里修改数据,可能导致循环
},
// 4. 卸载阶段(Vue 2 命名)
beforeDestroy() { // Vue 3 中仍可用,但建议用 beforeUnmount
console.log('beforeDestroy')
},
destroyed() { // Vue 3 中仍可用,但建议用 unmounted
console.log('destroyed')
},
// 5. keep-alive 相关
activated() {
console.log('activated')
},
deactivated() {
console.log('deactivated')
},
// 6. 错误处理(Vue 2.5+)
errorCaptured(err, instance, info) {
console.error('错误捕获:', err)
// 可以返回 false 阻止错误继续向上传播
return false
}
}
</script>
四、生命周期使用统计
根据实际项目经验,各生命周期使用频率:
-
高频使用 (80% 场景):
-
onMounted- DOM操作、数据请求、事件监听 -
onUnmounted- 清理工作
-
-
中频使用 (15% 场景):
-
onUpdated- 第三方库集成 -
onBeforeUnmount- 确保清理
-
-
低频使用 (5% 场景):
-
onBeforeMount- 服务端渲染特殊需求 -
onBeforeUpdate- 特定优化场景 -
onActivated/onDeactivated- 使用 keep-alive 时
-