一、先理解:什么是“生命周期”?
- 今天咱们来学习 Vue3 的 “生命周期”——它就像“组件的一生”,从“出生”(创建)到“工作”(更新)再到“死亡”(卸载),每个阶段都有对应的“钩子函数”,让我们能在特定时机执行代码(比如初始化数据、发送请求、清理定时器等)。
- 我们会用 “人生阶段”类比 理解生命周期,并结合 Vue3 组合式 API(
<script setup>)的写法,通过 2 个实战案例 掌握用法,保证你学得明明白白!- 每个 Vue 组件从创建到销毁,会经历一系列固定的“阶段”,就像人会经历“婴儿期→童年→成年→老年”一样。Vue 允许我们在这些阶段“插入”自定义代码,这些代码所在的函数就叫 “生命周期钩子函数”。
举个例子:
- 组件“刚出生”(创建阶段):需要初始化数据(比如从本地存储加载数据)
- 组件“挂载到页面”(挂载阶段):需要操作DOM(比如获取元素尺寸、初始化第三方插件)
- 组件“数据更新”(更新阶段):需要根据新数据执行动画或计算
- 组件“被销毁”(卸载阶段):需要清理定时器,取消网络请求(避免内存泄漏)
二、Vue3 组件的“一生”:8 个核心生命周期阶段
Vue3组合式API中,生命周期钩子函数需要从vue导入后使用,命名以onXxx开头。下面用“人生阶段类比,帮你记住每个钩子的作用”:
页面和组件的生命周期 生命周期阶段 钩子函数(Vue3组合式) 类比人生阶段 核心作用 1、组件创建前 onBeforeCreat 胎儿期(未出生) 组件实例刚创建,数据和DOM都未初始化(几乎不同,了解即可) 2、组件创建后 onCreated 刚出生(婴儿期) 数据已初始化(data|Props可用),但DOM未生成(可用于初始化数据,发请求) 3、组件挂载前 onBeforeMount 准备上学(5岁) DOM模板已编译,但未挂载到页面(<div id ='app'>)还是空的 4、组件挂载后 onMounted 进入学校(6岁) DOM已挂载到页面(可操作DOM,比如获取元素、初始化插件) 5、组件更新前
(数据变化是)
onBeforeUpdate 成长中(每年生日前) 数据已更新,但DOM未重新渲染(可获取更新前的DOM状态) 6、组件更新后
(数据变化时)
onUpdated 生日后(长大一岁) 数据和DOM都已更新(可处理更新后的DOM操作,比如滚动到新位置) 7、组件卸载前 onBeforeUnmount 临终前(80岁) 组件即将被销毁(可清理定时器、取消网络请求、解绑事件监听) 8、组件卸载后 onUnmounted 死亡后 组件已销毁,DOM被溢出(几乎不用,了解即可) 重点记住 3 个最常用的钩子:
- onCreated(组件创建后):初始化数据、发请求(数据准备阶段)
- onMounted(组件挂载后):操作DOM(页面渲染完成后)
- onBeforeUnmount(组件卸载前):清理副作用(组件销毁前“善后”)
三、实战:用生命周期钩子实现“数据加载-->DOM操作-->清理”全流程"
以Todo应用为例,我们给它添加”加载动画-->数据请求-->页面渲染-->离开时清理的"的完整逻辑,看看各个钩子的实际用法
- 步骤①:准备组件和基础代码
- 创建TodoLifecycle.vue组件,先搭建基本结构:
<template>
<div class="todo-container">
<!-- 加载动画(初始显示,数据加载完隐藏) -->
<div v-if="isLoading" class="loading">加载中...</div>
<!-- Todo 列表(数据加载完显示) -->
<div v-else>
<div v-for="(todo, index) in todos" :key="index">
{{ todo.text }}
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
// 响应式变量
const todos = ref([]); // Todo 列表数据
const isLoading = ref(true); // 加载状态(true:显示加载动画,false:隐藏)
const timer = ref(null); // 定时器(用于演示清理)
</script>
步骤②:用onCreated发送网络请求获取数据(模拟从后端加载Todo列表)
<script setup>
import { ref, onCreated } from 'vue'; // 导入 onCreated
// ... 变量定义 ...
// 组件创建后执行(初始化数据)
onCreated(() => {
console.log('onCreated:组件创建完成,开始请求数据');
// 模拟网络请求(2秒后获取数据)
timer.value = setTimeout(() => {
todos.value = [
{ text: '学习 onCreated 钩子' },
{ text: '掌握 onMounted 操作 DOM' }
];
isLoading.value = false; // 数据加载完,隐藏加载动画
}, 2000);
});
</script>
为什么用
onCreated而不是直接写代码?
- 直接在
<script setup>顶层写的代码会在“组件创建前”执行,此时todos等响应式变量可能还未初始化。onCreated保证在组件“数据初始化完成后”执行,更安全。
步骤③:用
onMounted操作 DOM(获取元素尺寸)组件挂载到页面后(DOM已生成),可以安全的操作DOM。比如获取Todo列表的宽度:
<script setup>
import { ref, onCreated, onMounted } from 'vue'; // 导入 onMounted
// ... 其他代码 ...
// 组件挂载到页面后执行(操作 DOM)
onMounted(() => {
console.log('onMounted:组件已挂载到页面,开始操作 DOM');
// 获取 .todo-container 元素的宽度(必须在 onMounted 中,否则元素还未生成)
const container = document.querySelector('.todo-container');
console.log('Todo 列表容器宽度:', container.offsetWidth); // 例如:300px
});
</script>
注意:
- 不能在onCreated中操作DOM,因为此时组件还未挂载到页面,DOM元素不存在
onMounted是最常用的钩子之一,适合初始化依赖 DOM 的插件(如 ECharts、地图等)
步骤④:用
onBeforeUnmount清理副作用(避免内存泄漏)当组件被销毁(比如页面导航离开)时,需要清理定时器、取消网络请求等“副作用”,否则会导致内存泄漏(定时器一直运行,占用资源)
- 假设我们在onCreated中创建了一个定时器,需要在组件销毁前清楚他:
<script setup>
import { ref, onCreated, onMounted, onBeforeUnmount } from 'vue'; // 导入 onBeforeUnmount
// ... 其他代码 ...
// 组件即将被销毁时执行(清理工作)
onBeforeUnmount(() => {
console.log('onBeforeUnmount:组件即将销毁,清理定时器');
// 清除定时器(如果不清理,组件销毁后定时器仍会执行)
clearTimeout(timer.value);
// 如果有网络请求,也需要在这里取消(如 axios 的 cancelToken)
});
</script>
什么是“内存泄漏”?
如果不清理定时器,即使组件被销毁,定时器依然会在后台运行,占用内存,久而久之会导致页面拉顿。OnBeforeUnmounted就是“最后的机会”来做“善后工作”
步骤⑤:运行效果和控制台输出
- 组件刚加载时:
onCreated执行 → 打印“开始请求数据”→ 显示“加载中...”。- 2 秒后:数据加载完成 →
isLoading变为 false → 隐藏加载动画,显示 Todo 列表。- 组件挂载完成:
onMounted执行 → 打印“组件已挂载”和容器宽度。- 当组件被销毁(比如导航到其他页面):
onBeforeUnmount执行 → 打印“清理定时器”→ 清除定时器。
四、Vue3 vs Vue2 生命周期钩子对比(快速参考)
如果你之前了解过 Vue2,这里对比一下两种写法的钩子名称,方便迁移:
Vue2 Options API 钩子 Vue3 组合式 API 钩子 变化说明 beforeCreateonBeforeCreate功能相同,名称加 oncreatedonCreated功能相同,名称加 onbeforeMountonBeforeMount功能相同,名称加 onmountedonMounted功能相同,名称加 onbeforeUpdateonBeforeUpdate功能相同,名称加 onupdatedonUpdated功能相同,名称加 onbeforeDestroyonBeforeUnmount功能相同,名称改为 onBeforeUnmount(更准确)destroyedonUnmounted功能相同,名称改为 onUnmounted
五、进阶:生命周期执行顺序和常见问题
1、钩子执行顺序
当多个钩子同时存在时,执行顺序固定为:
onBeforeCreat→
onCreated→onBeforeMount→onMounted→(数据更新时)onBeforeUpdate→onUpdated→(组件销毁时)onBeforeUnmount→onUnmounted2、避免在
onUpdated中修改数据(可能导致死循环)
onUpdated在数据更新后执行,如果你在onUpdated中再次修改数据,会触发新一轮更新,导致无限循环:onUpdated(() => { // 危险!todos 变化会再次触发 onUpdated,导致死循环 todos.value.push({ text: '新增待办' }); });3.
onMounted中获取不到子组件 DOM?如果父组件
onMounted中要获取子组件的 DOM,可能因为子组件还未挂载完成。此时可以:
- 给子组件添加
ref属性,通过$refs获取(需配合nextTick)。- 在子组件自己的
onMounted中处理 DOM 操作(职责分离,更推荐)。
六、总结:3 个必须掌握的核心钩子
1、oncreated:初始化数据、发送网络请求(组件“刚出生”就干的事)
2、onmounted:操作DOM、初始化第三方插件(组件“挂载到页面”后干的事)
3、onbeforeUnmount:清理定时器、取消请求(组件“销毁前”的“善后工作”)
住这三个钩子,就能解决 90% 的生命周期场景!
740

被折叠的 条评论
为什么被折叠?



