Vue 生命周期
每个 Vue 组件实例在创建时都会经历一系列初始化步骤:数据观测、模板编译、挂载到 DOM,以及数据更新时重新渲染。在这个过程中,Vue 会调用对应的生命周期钩子函数,让开发者可以在特定阶段执行自己的逻辑。
生命周期图示
生命周期钩子
beforeCreate
在实例初始化之后、data 和 methods 设置之前被调用。此时:
- 组件实例刚创建
data、methods不可用$refs为空对象
<script setup>
import { ref } from 'vue'
const count = ref(0) // count 是 undefined
console.log('beforeCreate:', count.value) // undefined
// setup() 相当于 beforeCreate + created
</script>
提示
在使用 <script setup> 时,组合式 API 的 setup() 函数会在 beforeCreate 之前被调用。
created
在实例创建完成后被调用。此时:
data和methods已经设置完成$refs可用- 但 DOM 还未挂载,不能访问
$el
<script setup>
import { ref, onMounted } from 'vue'
const count = ref(0)
console.log('created:', count.value) // 0
// 常用于:初始化数据、调用 API、设置监听器
onMounted(() => {
console.log('mounted:', count.value) // DOM 已挂载
})
</script>
beforeMount
在模板编译完成、挂载到 DOM 之前被调用。此时:
- 模板已经编译成渲染函数
- DOM 还未真正挂载
<script setup>
import { ref } from 'vue'
const message = ref('Hello')
// 很少使用
</script>
mounted
在实例挂载到 DOM 后被调用。此时:
$el、$refs可用- 可以访问到真实的 DOM 元素
- 常用于:初始化第三方库、操作 DOM
<script setup>
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
const chartRef = ref(null)
onMounted(() => {
// DOM 已挂载,可以操作
const chart = echarts.init(chartRef.value)
chart.setOption({ /* 配置 */ })
})
// 清理工作
import { onUnmounted } from 'vue'
onUnmounted(() => {
// 销毁图表实例
chart?.dispose()
})
</script>
<template>
<div ref="chartRef" style="width: 100%; height: 400px;"></div>
</template>
beforeUpdate
在响应式数据变化、DOM 重新渲染之前被调用。此时:
- 可以获取更新前的状态
- 适合在 DOM 更新前做额外处理
<script setup>
import { ref, onBeforeUpdate } from 'vue'
const count = ref(0)
onBeforeUpdate(() => {
console.log('更新前:', count.value)
})
</script>
updated
在 DOM 重新渲染完成后被调用。此时:
- DOM 已经更新
- 避免在 updated 中修改状态,可能导致无限循环
<script setup>
import { ref, onUpdated } from 'vue'
const count = ref(0)
onUpdated(() => {
console.log('更新后: DOM 已更新')
})
</script>
beforeUnmount
在组件实例卸载之前被调用。此时:
- 组件实例仍然完全可用
- 常用于:清理定时器、取消订阅、移除事件监听
<script setup>
import { ref, onBeforeUnmount } from 'vue'
const timer = setInterval(() => {
console.log('interval')
}, 1000)
onBeforeUnmount(() => {
clearInterval(timer) // 清理定时器
})
</script>
unmounted
在组件实例卸载完成后被调用。此时:
- 所有子组件已卸载
- 所有指令已解除绑定
- 事件监听已移除
- 常用于:清理组件相关的资源
<script setup>
import { ref, onUnmounted } from 'vue'
onUnmounted(() => {
console.log('组件已卸载')
})
</script>
组合式 API 中的生命周期钩子
在 <script setup> 中使用组合式 API 的生命周期钩子:
import {
onMounted,
onUpdated,
onUnmounted,
onBeforeMount,
onBeforeUpdate,
onBeforeUnmount,
onErrorCaptured,
onRenderTracked,
onRenderTriggered
} from 'vue'
| 选项式 API | 组合式 API |
|---|---|
| beforeCreate | 不需要(setup 替代) |
| created | 不需要(setup 替代) |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
| errorCaptured | onErrorCaptured |
| renderTracked | onRenderTracked |
| renderTriggered | onRenderTriggered |
实际应用示例
示例:数据获取
<script setup>
import { ref, onMounted } from 'vue'
const users = ref([])
const loading = ref(true)
const error = ref(null)
async function fetchUsers() {
try {
loading.value = true
const response = await fetch('/api/users')
users.value = await response.json()
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
}
onMounted(() => {
fetchUsers()
})
</script>
示例:定时器管理
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const time = ref(new Date())
let timer = null
onMounted(() => {
timer = setInterval(() => {
time.value = new Date()
}, 1000)
})
onUnmounted(() => {
if (timer) {
clearInterval(timer)
}
})
</script>
示例:窗口监听器
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const windowWidth = ref(window.innerWidth)
function handleResize() {
windowWidth.value = window.innerWidth
}
onMounted(() => {
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
</script>
示例:错误处理
<script setup>
import { ref, onErrorCaptured } from 'vue'
const error = ref(null)
onErrorCaptured((err, instance, info) => {
error.value = err.message
console.error('错误信息:', err)
console.error('错误组件:', instance)
console.error('错误详情:', info)
return false // 阻止错误继续传播
})
</script>
父子组件生命周期顺序
创建时:父 beforeCreate → 父 created → 父 beforeMount → 子 beforeCreate → 子 created → 子 beforeMount → 子 mounted → 父 mounted
卸载时:父 beforeUnmount → 子 beforeUnmount → 子 unmounted → 父 unmounted
小结
本章我们详细学习了 Vue 生命周期的完整内容:
- 生命周期图示:了解各阶段的执行顺序
- 各阶段钩子函数:beforeCreate 到 unmounted
- 组合式 API 钩子:onMounted、onUnmounted 等
- 实际应用:数据获取、定时器、事件监听、错误处理
- 父子组件顺序:创建和卸载时的执行顺序
练习
- 创建一个自动刷新数据的组件
- 创建一个带有清理功能的组件
- 实现一个错误边界组件
准备好进入下一章,学习 ref 和 reactive 的内容了吗?