Vue3 组件的“一生”:8 个核心生命周期阶段

一、先理解:什么是“生命周期”?

  • 今天咱们来学习 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就是“最后的机会”来做“善后工作”

步骤⑤:运行效果和控制台输出

  1. 组件刚加载时:onCreated 执行 → 打印“开始请求数据”→ 显示“加载中...”。
  2. 2 秒后:数据加载完成 → isLoading 变为 false → 隐藏加载动画,显示 Todo 列表。
  3. 组件挂载完成:onMounted 执行 → 打印“组件已挂载”和容器宽度。
  4. 当组件被销毁(比如导航到其他页面):onBeforeUnmount 执行 → 打印“清理定时器”→ 清除定时器。

四、Vue3 vs Vue2 生命周期钩子对比(快速参考)

如果你之前了解过 Vue2,这里对比一下两种写法的钩子名称,方便迁移:

Vue2 Options API 钩子Vue3 组合式 API 钩子变化说明
beforeCreateonBeforeCreate功能相同,名称加 on
createdonCreated功能相同,名称加 on
beforeMountonBeforeMount功能相同,名称加 on
mountedonMounted功能相同,名称加 on
beforeUpdateonBeforeUpdate功能相同,名称加 on
updatedonUpdated功能相同,名称加 on
beforeDestroyonBeforeUnmount功能相同,名称改为 onBeforeUnmount(更准确)
destroyedonUnmounted功能相同,名称改为 onUnmounted

五、进阶:生命周期执行顺序和常见问题

1、钩子执行顺序

当多个钩子同时存在时,执行顺序固定为:

onBeforeCreat→ onCreatedonBeforeMountonMounted →(数据更新时)onBeforeUpdateonUpdated →(组件销毁时)onBeforeUnmountonUnmounted

2、避免在 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% 的生命周期场景!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值