vue 生命周期
生命周期钩子:https://cn.vuejs.org/guide/essentials/lifecycle.html
组合式 API:生命周期钩子:https://cn.vuejs.org/api/composition-api-lifecycle.html
每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。
人的 - 生命周期
组件从创建到销毁的整个过程就是组件的生命周期
生命周期图示
下面是实例生命周期的图表。你现在并不需要完全理解图中的所有内容,但以后它将是一个有用的参考。
有关所有生命周期钩子及其各自用例的详细信息,请参考生命周期钩子 API 索引。
注册周期钩子
举例来说,onMounted
钩子可以用来在组件完成初始渲染并创建 DOM 节点后运行代码:
<script setup>
import { onMounted } from "vue";
onMounted(() => {
console.log(`the component is now mounted.`);
});
</script>
还有其他一些钩子,会在实例生命周期的不同阶段被调用,最常用的是 onMounted
、onUpdated
和 onUnmounted
。所有生命周期钩子的完整参考及其用法请参考 API 索引。
当调用 onMounted
时,Vue 会自动将回调函数注册到当前正被初始化的组件实例上。这意味着这些钩子应当在组件初始化时被同步 注册。例如,请不要这样做:
setTimeout(() => {
onMounted(() => {
// 异步注册时当前组件实例已丢失
// 这将不会正常工作
});
}, 100);
注意这并不意味着对 onMounted
的调用必须放在 setup()
或 <script setup>
内的词法上下文中。onMounted()
也可以在一个外部函数中调用,只要调用栈是同步的,且最终起源自 setup()
就可以。
钩子函数
Vue 框架内置函数,随着组件的生命周期阶段,自动执行
作用:特定的时间点,执行特定的操作
场景:组件创建完毕后,可以在 created 生命周期函数中发起 Ajax 请求,从而初始化 data 数据
分类:4 大阶段 8 个方法
- 初始化
- 挂载
- 更新
- 销毁
阶段 | 方法名 | 方法名 |
---|---|---|
初始化 | beforeCreate | created |
挂载 | beforeMount | mounted |
更新 | beforeUpdate | updated |
销毁 | beforeDestroy | destroyed |
Vue2.x 和 Vue3.x 生命周期对比
初始化阶段
- Vue.createApp(options)– Vue 实例化 (组件也是一个小的 Vue 实例)
- Init events & lifecycle – 初始化事件和生命周期函数
- beforeCreate – 生命周期钩子函数被执行
- Init injections&reactivity – Vue 内部添加 data 和 methods 等
- created – 生命周期钩子函数被执行,实例创建
- 接下来是编译模板阶段 –开始分析
- Has el option? – 是否有 el 选项 – 检查要挂到哪里
- 没有。调用
$mount()
方法 - 有,继续检查 template 选项
- 没有。调用
<script setup>
import { ref } from "vue";
const msg = ref("hello Vue !");
// 一。初始化
// Vue.createApp 以后,vue 内部给实例对象添加了一些属性和方法,data 和 methods 初始化"之前"
// beforeCreate --> setup()
// created --> setup()
</script>
挂载阶段
含义讲解:
- template 选项检查
- 有 - 编译 template 返回 render 渲染函数
- 无 – 编译 el 选项对应标签作为 template (要渲染的模板)
- 虚拟 DOM 挂载成真实 DOM 之前
- beforeMount – 生命周期钩子函数被执行
- Create … – 把虚拟 DOM 和渲染的数据一并挂到真实 DOM 上
- 真实 DOM 挂载完毕
- mounted – 生命周期钩子函数被执行
<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>
更新阶段
- 当 data 里数据改变,更新 DOM 之前
- beforeUpdate – 生命周期钩子函数被执行
- Virtual DOM…… – 虚拟 DOM 重新渲染,打补丁到真实 DOM
- updated – 生命周期钩子函数被执行
- 当有 data 数据改变 – 重复这个循环
准备 ul+li 循环,按钮添加元素,触发 data 改变->导致更新周期开始
<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>
销毁阶段
- 当
$destroy()
被调用 – 比如组件 DOM 被移除 (例 v-if) - beforeDestroy – 生命周期钩子函数被执行
- 拆卸数据监视器、子组件和事件侦听器
- 实例销毁后,最后触发一个钩子函数
- destroyed – 生命周期钩子函数被执行
<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 组件进入销毁阶段
<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.
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 以阻止该错误继续向上传播。