图秀主页
56.67M · 2026-02-04
生命周期钩子(Lifecycle Hooks)是 Vue 组件从诞生到销毁的全过程记录。掌握生命周期,不仅能让我们在正确的时间点执行逻辑,更是优化性能、排查内存泄露的关键。
Vue 的生命周期大体可分为:创建、挂载、更新、销毁。
在 Vue 3 组合式 API 中,生命周期钩子需要从 vue 中导入,且命名上增加了 on 前缀。
| 阶段 | Vue 2 (选项式 API) | Vue 3 (组合式 API) | 备注 |
|---|---|---|---|
| 创建 | beforeCreate / created | setup() | Vue 3 中 setup 包含了这两个时期 |
| 挂载 | beforeMount / mounted | onBeforeMount / onMounted | 常用:操作 DOM、请求接口 |
| 更新 | beforeUpdate / updated | onBeforeUpdate / onUpdated | 响应式数据变化时触发 |
| 销毁 | beforeDestroy / destroyed | onBeforeUnmount / onUnmounted | 注意:Vue 3 中命名的变更 |
| 缓存 | activated / deactivated | onActivated / onDeactivated | 配合 <keep-alive> 使用 |
Vue 2 (beforeCreate / created) :
beforeCreate:组件实例刚在内存中被创建,此时还没有初始化好 data 和 methods 属性。适合插件开发,注入全局变量。created:实例已创建,响应式数据data、methods 已准备好。
Vue 3 (setup) :
setup 的执行早于 beforeCreate,它是组合式 API 的入口。beforeMount / mounted) :
beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
mounted:此时已经将编译好的模板挂载到了页面指定的容器中,可以访问页面中的dom了
场景:dom已创建,可用于获取接口数据和dom元素、访问子组件
onBeforeMount / onMounted) :
onBeforeMount:模板编译完成,但尚未渲染到 DOM 树中。
onMounted:组件已挂载,可以安全地访问 DOM 元素。
Vue 2 (beforeUpdate / updated) :
beforeUpdate:数据状态更新之前执行,此时 data 中的状态值是最新的,但是界面上显示的数据还是旧的,因为此时还没有开始重新渲染DOM节点。
updated:实例更新完毕之后调用,此时 data 中的状态值和界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了。
Vue 3 (onBeforeUpdate / onUpdated) :
onBeforeUpdate:数据已更新,但 DOM 尚未重新渲染。可用于获取更新前的 DOM 状态。onUpdated:DOM 已完成更新。注意:不要在此钩子中修改状态,否则可能导致死循环。Vue 2 (beforeDestroy / destroyed) :
beforeDestroy:实例销毁之前调用。
setInterval)、解绑全局事件、取消订阅。destroyed:Vue 实例销毁后调用。组件彻底从 DOM 中移除,所有的指令和事件都会被解除。Vue 3 (onBeforeUnmount / onUnmounted) :
onBeforeUnmount:实例销毁之前调用。
onUnmounted:组件彻底从 DOM 中移除,所有的指令和事件都会被解除。
如果使用了keep-alive缓存组件会新增两个生命周期函数
onActivated:组件进入视野,被重新激活时调用。onDeactivated:组件移出视野,进入缓存状态时调用。以下是使用 script setup 语法编写的生命周期示例:
<template>
<div ref="container">
<h2>当前计数:{{ count }}</h2>
<button @click="count++">增加</button>
</div>
</template>
<script setup lang="ts">
import {
ref,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount
} from 'vue'
const count = ref<number>(0)
const container = ref<HTMLElement | null>(null)
let timer: number | null = null
// 挂载阶段
onMounted(() => {
console.log('Component Mounted. DOM element:', container.value)
// 模拟一个定时任务
timer = window.setInterval(() => {
console.log('Timer running...')
}, 1000)
})
// 运行阶段
onBeforeUpdate(() => {
console.log('Data updated, but DOM is not yet re-rendered.')
})
onUpdated(() => {
console.log('Data updated and DOM re-rendered.')
})
// 销毁阶段
onBeforeUnmount(() => {
console.log('Cleanup before unmount.')
if (timer) {
clearInterval(timer) // 关键:防止内存泄漏
}
})
</script>
为了清晰起见,我们将顺序拆解为三个主要场景(vue3):
父组件必须等待所有子组件挂载完成后,才能完成自己的挂载逻辑。
setup(开始创建)onBeforeMountsetuponBeforeMountonMounted (子组件渲染完毕,向上通知)onMounted (父组件接收到信号,宣布整体挂载完毕)当父组件传递给子组件的 props 发生变化时,更新逻辑如下:
onBeforeUpdateonBeforeUpdateonUpdatedonUpdated销毁过程同样是“递归”式的,父组件先启动销毁,等子组件销毁完毕后,父组件正式功成身退。
onBeforeUnmountonBeforeUnmountunmountedonUnmounted你可以通过以下代码在控制台直接观察执行逻辑。
Parent.vue<script setup lang="ts">
import { onMounted, onBeforeMount } from 'vue'
import Child from './Child.vue'
console.log('1. 父 - setup')
onBeforeMount(() => console.log('3. 父 - onBeforeMount'))
onMounted(() => console.log('8. 父 - onMounted'))
</script>
<template>
<div class="parent">
<h1>父组件</h1>
<Child />
</div>
</template>
Child.vue<script setup lang="ts">
import { onMounted, onBeforeMount } from 'vue'
console.log('4. 子 - setup')
onBeforeMount(() => console.log('6. 子 - onBeforeMount'))
onMounted(() => console.log('7. 子 - onMounted'))
</script>
<template>
<div class="child">子组件内容</div>
</template>
接口请求放哪里?
created(Vue 2)或 setup(Vue 3)中请求。onMounted 发请求,子组件此时也已经渲染完成了。Refs 访问时机:
ref 访问子组件实例,必须在父组件的 onMounted 之后,因为只有这时子组件才真正挂载完成。异步组件:
defineAsyncComponent),顺序会发生变化,父组件可能会先执行 onMounted。