跳到主要内容

Vue 生命周期

每个 Vue 组件实例在创建时都会经历一系列初始化步骤:数据观测、模板编译、挂载到 DOM,以及数据更新时重新渲染。在这个过程中,Vue 会调用对应的生命周期钩子函数,让开发者可以在特定阶段执行自己的逻辑。

生命周期图示

生命周期钩子

beforeCreate

在实例初始化之后、data 和 methods 设置之前被调用。此时:

  • 组件实例刚创建
  • datamethods 不可用
  • $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

在实例创建完成后被调用。此时:

  • datamethods 已经设置完成
  • $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 替代)
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered

实际应用示例

示例:数据获取

<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 生命周期的完整内容:

  1. 生命周期图示:了解各阶段的执行顺序
  2. 各阶段钩子函数:beforeCreate 到 unmounted
  3. 组合式 API 钩子:onMounted、onUnmounted 等
  4. 实际应用:数据获取、定时器、事件监听、错误处理
  5. 父子组件顺序:创建和卸载时的执行顺序

练习

  1. 创建一个自动刷新数据的组件
  2. 创建一个带有清理功能的组件
  3. 实现一个错误边界组件

准备好进入下一章,学习 ref 和 reactive 的内容了吗?