Vue3 生命周期

Vue3的生命周期:从创建到销毁的完整旅程

Vue3的生命周期是组件从创建到销毁的一系列有序阶段,每个阶段都对应着特定的钩子函数,允许开发者在关键时刻插入自定义逻辑。相比Vue2,Vue3不仅保留了核心生命周期概念,还通过Composition API提供了更灵活的使用方式。本文将详细解析Vue3的生命周期体系、钩子函数的作用及最佳实践。

一、生命周期的核心概念与阶段划分

生命周期本质上是组件实例在不同阶段触发的”事件”,这些事件反映了组件从初始化到最终卸载的完整生命周期。Vue3的生命周期可划分为4个核心阶段,每个阶段包含若干钩子函数:

1. 初始化阶段:组件创建与设置

  • 组件实例被创建,初始化响应式数据、事件监听等基础配置。

2. 挂载阶段:组件渲染到DOM

  • 组件模板被解析、编译为渲染函数,最终渲染为真实DOM并插入页面。

3. 更新阶段:响应式数据变化触发

  • 当响应式数据更新时,组件重新渲染,DOM发生更新。

4. 卸载阶段:组件从DOM中移除

  • 组件实例被销毁,清理事件监听、定时器等资源,避免内存泄漏。

二、Vue3的生命周期钩子函数

Vue3提供了两种使用生命周期钩子的方式:Options API(与Vue2兼容)和Composition API(通过onXxx函数)。两者功能一致,但Composition API更符合逻辑聚合的编程范式。

1. 初始化阶段钩子

(1)beforeCreate(Options API)

  • 触发时机:组件实例初始化后,响应式数据和事件系统设置之前。
  • 特点:此时无法访问datamethodsprops等,通常不常用。

(2)created(Options API)/ onMounted 前的初始化

  • 触发时机:组件实例创建完成,响应式数据、propsmethods已初始化。
  • 功能:可用于数据初始化、异步请求(如获取初始数据)、事件监听设置等。
  • Composition API对应:无直接对应钩子,可在setup函数中直接编写(setupbeforeCreatecreated之间执行)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Options API
export default {
data() { return { list: [] } },
created() {
// 初始化数据
this.fetchData()
},
methods: {
fetchData() { /* 异步请求 */ }
}
}

// Composition API
import { onMounted, ref } from 'vue'
export default {
setup() {
const list = ref([])
// 相当于created中执行(setup在created前触发,适合初始化)
const fetchData = async () => { /* 异步请求 */ }
fetchData()
return { list }
}
}

2. 挂载阶段钩子

(1)beforeMount(Options API)/ onBeforeMount(Composition API)

  • 触发时机:组件即将被挂载到DOM,此时模板已编译为渲染函数,但尚未生成真实DOM。
  • 特点:无法访问DOM元素($el未创建),可用于最后一次数据修改。

(2)mounted(Options API)/ onMounted(Composition API)

  • 触发时机:组件已挂载到DOM,真实DOM元素可用。
  • 功能:最常用的钩子之一,适合执行依赖DOM的操作(如初始化第三方UI库、设置DOM尺寸、绑定DOM事件)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Composition API示例
import { onMounted, ref } from 'vue'
export default {
setup() {
const container = ref(null)

onMounted(() => {
// 访问DOM元素(通过ref绑定)
console.log('容器高度:', container.value.offsetHeight)
// 初始化依赖DOM的库(如Chart.js)
new Chart(container.value, { /* 配置 */ })
})

return { container }
}
}

3. 更新阶段钩子

当组件的响应式数据发生变化时,会触发更新阶段,执行重新渲染逻辑。

(1)beforeUpdate(Options API)/ onBeforeUpdate(Composition API)

  • 触发时机:响应式数据更新后,DOM更新前。
  • 功能:可访问更新前的DOM状态,常用于获取更新前的DOM信息(如滚动位置)。

(2)updated(Options API)/ onUpdated(Composition API)

  • 触发时机:DOM已完成更新(数据变化导致的重新渲染已完成)。
  • 功能:可执行依赖更新后DOM的操作(如重新计算布局、同步DOM状态)。
  • 注意:避免在updated中修改响应式数据(可能导致无限循环更新)。
1
2
3
4
5
// 监听列表更新后滚动到底部
onUpdated(() => {
const listEl = document.getElementById('list')
listEl.scrollTop = listEl.scrollHeight
})

4. 卸载阶段钩子

当组件被移除(如路由切换、v-iffalse)时,触发卸载阶段,用于清理资源。

(1)beforeUnmount(Options API)/ onBeforeUnmount(Composition API)

  • 触发时机:组件即将被卸载,此时组件实例仍完整,DOM仍存在。
  • 功能:主要用于清理资源(如移除事件监听、清除定时器、取消未完成的请求)。

(2)unmounted(Options API)/ onUnmounted(Composition API)

  • 触发时机:组件已被完全卸载,DOM元素已移除,事件监听等已清理。
  • 功能:可执行最终的资源释放操作(如销毁第三方库实例、释放内存缓存)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 清理定时器示例
import { onMounted, onBeforeUnmount, ref } from 'vue'
export default {
setup() {
let timer = null
const count = ref(0)

onMounted(() => {
timer = setInterval(() => {
count.value++
}, 1000)
})

onBeforeUnmount(() => {
// 组件卸载前清除定时器
clearInterval(timer)
})

return { count }
}
}

5. 其他特殊生命周期钩子

(1)onErrorCaptured

  • 功能:捕获子组件抛出的错误(包括同步错误和异步错误),返回true可阻止错误继续向上传播。
  • 用途:全局错误处理、错误日志上报、展示友好错误提示。
1
2
3
4
5
onErrorCaptured((err, instance, info) => {
console.error('捕获错误:', err, '组件:', instance, '信息:', info)
// 返回true阻止错误冒泡
return true
})

(2)onActivated / onDeactivated

  • 适用场景:配合<KeepAlive>组件使用,当组件被激活/失活时触发。
  • 用途:在组件缓存时执行初始化/清理逻辑(如恢复滚动位置、重新播放动画)。
1
2
3
4
// 缓存组件激活时重置数据
onActivated(() => {
resetForm()
})

三、Options API与Composition API钩子对比

Options API钩子 Composition API钩子 触发时机 核心作用
beforeCreate -(在setup中执行) 组件实例初始化后 初始化非响应式数据
created -(在setup中执行) 组件实例创建完成 数据请求、事件监听设置
beforeMount onBeforeMount 组件挂载前 最后一次数据修改
mounted onMounted 组件挂载完成 DOM操作、第三方库初始化
beforeUpdate onBeforeUpdate 数据更新后,DOM更新前 获取更新前DOM状态
updated onUpdated DOM更新完成 依赖更新后DOM的操作
beforeUnmount onBeforeUnmount 组件卸载前 清理资源(定时器、事件监听)
unmounted onUnmounted 组件卸载完成 最终资源释放

四、生命周期使用的最佳实践

  1. 避免在mounted中依赖子组件DOM
    父组件的mounted可能早于子组件的mounted执行,若需操作子组件DOM,可使用nextTickonUpdated

    1
    2
    3
    4
    5
    6
    onMounted(() => {
    // 确保子组件已渲染
    nextTick(() => {
    const childEl = document.querySelector('.child')
    })
    })
  2. 清理资源是核心责任
    所有手动创建的资源(定时器、事件监听、WebSocket连接、第三方库实例)必须在onBeforeUnmount中清理,否则会导致内存泄漏。

  3. 拆分逻辑与生命周期
    使用Composition API时,建议按功能拆分代码(如表单逻辑、列表逻辑),每个功能内聚合相关的生命周期钩子,而非集中在一个setup中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 按功能拆分逻辑
    function useFormLogic() {
    onMounted(() => { /* 表单初始化 */ })
    onBeforeUnmount(() => { /* 表单清理 */ })
    }

    function useListLogic() {
    onMounted(() => { /* 列表加载 */ })
    onBeforeUnmount(() => { /* 列表清理 */ })
    }

    export default {
    setup() {
    useFormLogic()
    useListLogic()
    }
    }
  4. 优先使用onBeforeUnmount而非onUnmounted
    组件卸载前(onBeforeUnmount)DOM仍存在,此时清理资源更可靠(如移除基于DOM的事件监听)。

五、总结

Vue3的生命周期钩子为开发者提供了精确控制组件行为的能力,从初始化到卸载的每个阶段都有明确的钩子函数对应。相比Vue2,Composition API的onXxx钩子更灵活,可按逻辑拆分而非集中在选项中,大幅提升了代码的可维护性。

掌握生命周期的核心在于理解”何时执行何种操作”:初始化数据放在setupcreated,DOM操作放在mounted,资源清理放在beforeUnmount。合理利用生命周期钩子,能让组件更高效、更健壮地运行。