Skip to content

vue 生命周期

生命周期钩子:https://cn.vuejs.org/guide/essentials/lifecycle.html

组合式 API:生命周期钩子:https://cn.vuejs.org/api/composition-api-lifecycle.html

每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。

人的 - 生命周期

image-20210111193143574

组件从创建到销毁的整个过程就是组件的生命周期

生命周期图示

下面是实例生命周期的图表。你现在并不需要完全理解图中的所有内容,但以后它将是一个有用的参考。

lifecycle

有关所有生命周期钩子及其各自用例的详细信息,请参考生命周期钩子 API 索引

注册周期钩子

举例来说,onMounted 钩子可以用来在组件完成初始渲染并创建 DOM 节点后运行代码:

vue
<script setup>
import { onMounted } from "vue";

onMounted(() => {
  console.log(`the component is now mounted.`);
});
</script>

还有其他一些钩子,会在实例生命周期的不同阶段被调用,最常用的是 onMountedonUpdatedonUnmounted 。所有生命周期钩子的完整参考及其用法请参考 API 索引

当调用 onMounted 时,Vue 会自动将回调函数注册到当前正被初始化的组件实例上。这意味着这些钩子应当在组件初始化时被同步 注册。例如,请不要这样做:

js
setTimeout(() => {
  onMounted(() => {
    // 异步注册时当前组件实例已丢失
    // 这将不会正常工作
  });
}, 100);

注意这并不意味着对 onMounted 的调用必须放在 setup()<script setup> 内的词法上下文中。onMounted() 也可以在一个外部函数中调用,只要调用栈是同步的,且最终起源自 setup() 就可以。

钩子函数

Vue 框架内置函数,随着组件的生命周期阶段,自动执行

作用:特定的时间点,执行特定的操作

场景:组件创建完毕后,可以在 created 生命周期函数中发起 Ajax 请求,从而初始化 data 数据

分类:4 大阶段 8 个方法

  • 初始化
  • 挂载
  • 更新
  • 销毁
阶段方法名方法名
初始化beforeCreatecreated
挂载beforeMountmounted
更新beforeUpdateupdated
销毁beforeDestroydestroyed

Vue2.x 和 Vue3.x 生命周期对比

img

初始化阶段

  1. Vue.createApp(options)– Vue 实例化 (组件也是一个小的 Vue 实例)
  2. Init events & lifecycle – 初始化事件和生命周期函数
  3. beforeCreate – 生命周期钩子函数被执行
  4. Init injections&reactivity – Vue 内部添加 data 和 methods 等
  5. created – 生命周期钩子函数被执行,实例创建
  6. 接下来是编译模板阶段 –开始分析
  7. Has el option? – 是否有 el 选项 – 检查要挂到哪里
    • 没有。调用 $mount() 方法
    • 有,继续检查 template 选项
vue
<script setup>
import { ref } from "vue";

const msg = ref("hello Vue !");

// 一。初始化
// Vue.createApp 以后,vue 内部给实例对象添加了一些属性和方法,data 和 methods 初始化"之前"
// beforeCreate  -->  setup()
// created       -->  setup()
</script>

挂载阶段

含义讲解:

  1. template 选项检查
    • 有 - 编译 template 返回 render 渲染函数
    • 无 – 编译 el 选项对应标签作为 template (要渲染的模板)
  2. 虚拟 DOM 挂载成真实 DOM 之前
  3. beforeMount – 生命周期钩子函数被执行
  4. Create … – 把虚拟 DOM 和渲染的数据一并挂到真实 DOM 上
  5. 真实 DOM 挂载完毕
  6. mounted – 生命周期钩子函数被执行
vue
<script setup>
import { onBeforeMount, ref, onMounted, reactive } from "vue";

const msg = ref("hello vue life !");

// 二。挂载
// 真实 DOM 挂载之前
// 场景:预处理 data, 不会触发 updated 钩子函数
onBeforeMount(() => {
  console.log("在 vue 元素挂在之前的事件");
  // console.log(document.querySelector('.main'))
});

// 真实 DOM 挂载以后
// 场景:挂载后真实 DOM
onMounted(() => {
  console.log("在 vue 元素挂载完毕之后");
  // 挂在好之后请求服务器获取后端数据,渲染到页面上
  // console.log(document.querySelector('.main'))
});
</script>

<template>
  <div class="main">
    <p>学习生命周期 - 看控制台打印</p>
    {{ msg }}
  </div>
</template>

更新阶段

  1. 当 data 里数据改变,更新 DOM 之前
  2. beforeUpdate – 生命周期钩子函数被执行
  3. Virtual DOM…… – 虚拟 DOM 重新渲染,打补丁到真实 DOM
  4. updated – 生命周期钩子函数被执行
  5. 当有 data 数据改变 – 重复这个循环

准备 ul+li 循环,按钮添加元素,触发 data 改变->导致更新周期开始

vue
<script setup>
import { onBeforeUpdate, ref, onUpdated, reactive } from "vue";

const msg = ref("hello Vue !");
const arr = reactive(["橘子", "苹果", "梨子"]);

// 三。更新
// 前提:data 数据改变才执行
// 更新之前

onBeforeUpdate(() => {
  console.log("在 vue 组件更新之前");
  // console.log(document.querySelectorAll("#myUL>li")[4]); // undefined
});

// 更新之后
// 场景:获取更新后的真实 DOM
onUpdated(() => {
  console.log("在 vue 组件更新之后");
  console.log(document.querySelectorAll("#myUL>li")[4]); // li
});
</script>

<template>
  <div>
    <ul id="myUL">
      <li v-for="(val, index) in arr" :key="index">
        {{ val }}
      </li>
    </ul>
    <button @click="arr.push('西瓜')">点击末尾加值</button>
  </div>
</template>

销毁阶段

  1. $destroy() 被调用 – 比如组件 DOM 被移除 (例 v-if)
  2. beforeDestroy – 生命周期钩子函数被执行
  3. 拆卸数据监视器、子组件和事件侦听器
  4. 实例销毁后,最后触发一个钩子函数
  5. destroyed – 生命周期钩子函数被执行
vue
<script setup>
import { onBeforeUnmount, onUnmounted, ref } from "vue";

// 四。销毁
// 前提:v-if="false" 销毁 Vue 实例
// 场景:移除全局事件,移除当前组件,计时器,定时器,eventBus 移除事件$off 方法
onBeforeUnmount(() => {
  console.log("即将就销毁当前组件");
  // 关闭某一个组件让用户进行确认
});

onUnmounted(() => {
  console.log("已经销毁当前组件");
});
</script>

主要:App.vue - 点击按钮让 Life 组件从 DOM 上移除 -> 导致 Life 组件进入销毁阶段

vue
<script setup>
import Life from "./components/Life.vue";
import { ref } from "vue";

const is_show = ref(true);
</script>

<template>
  <div>
    <!--    v-show 触发的时候是更新状态 -->
    <!--    <Life v-show="is_show"></Life>-->

    <!--    v-if 是销毁/重建元素-->
    <Life v-if="is_show"></Life>
    <button @click="is_show = !is_show">点击</button>
    <button @click="is_show = !is_show">点击</button>
  </div>
</template>

总结:

生命周期的阶段?(必会)

Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载 Dom → 渲染、更新 → 渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。

1)beforeCreate

在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。

2)created

在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

3)beforeMount

在挂载开始之前被调用:相关的 render 函数首次被调用。

4)mounted

el 被新创建的 vm.elrootmountedvm.el 也在文档内。

5)beforeUpdate

数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。

6)updated

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

7)activated

keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。

8)deactivated

keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。

9)beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。

10)destroyed

Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

11)errorCaptured(2.5.0+ 新增)

当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。