vue2与vue3中生命周期执行顺序区别
生命周期比较
简单例子说明
三种情况下的生命周期执行顺序
1、单页面下生命周期顺序
2、父子、兄弟组件的生命周期顺序
3、不同页面跳转时各页面生命周期的执行顺序
vue2与vue3中生命周期执行顺序区别 生命周期比较vue2中执行顺序 beforeCreate
=>created
=>beforeMount
=>mounted
=>beforeUpdate
=>updated
=>beforeDestroy
=>destroyed
vue3中执行顺序 setup
=>onBeforeMount
=>onMounted
=>onBeforeUpdate
=>onUpdated
=>onBeforeUnmount
=>onUnmounted
对应关系
vue2->vue3
beforeCreate
->setup
created
-> setup
beforeMount
-> onBeforeMount
mounted
-> onMounted
beforeUpdate
-> onBeforeUpdate
updated
-> onUpdated
beforeDestroy
-> onBeforeUnmount
destroyed
-> onUnmounted
其中 vue3中的setup相当于vue2中beforeCreate 与created 但是的执行在beforeCreate 与created之前,所以setup无法使用 data 和 methods 中的数据和方法,即无法操作this,setup中的this等于 undefined,又因为setup中创建的变量与方法最后都要通过return返回出去,所以setup中的程序只能是同步的,而不能是异步,除非return 后面只接受一个异步对象,对象返回setup内定义的变量与方法,然后父组件使用Suspense标签包裹异步组件;
vue3中 如果要使用vue2的beforeDestroy与destroyed需要把名称分别改为beforeUnmount,unmounted
如果vue3中同时使用了vue2的写法,vue3的写法会优先执行;
简单例子说明父组件App.vue
<template>
<h1>App父级组件</h1>
<button @click="childShow = !childShow">切换child子组件的显示</button>
<hr />
<child v-if="childShow" />
</template>
<script lang="ts">
import { defineComponent, reactive, ref } from "vue";
//引入子组件
import child from "./components/child.vue";
export default defineComponent({
name: "App",
components: {
child,
},
setup() {
const childShow = ref(true);
return {
childShow,
};
},
});
</script>
<style>
* {
margin: 0;
padding: 0;
}
</style>
子组件child.vue
<template>
<h2>child 子级组件</h2>
<h3>{{ name }}</h3>
<button @click="updateName">更新name</button>
</template>
<script lang="ts">
import {
defineComponent,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
ref,
} from "vue";
export default defineComponent({
name: "child",
//vue2中的生命周期钩子
beforeCreate() {
console.log("vue2 中的生命周期 beforeCreate");
},
created() {
console.log("vue2 中的生命周期 created");
},
beforeMount() {
console.log("vue2 中的生命周期 beforeMount");
},
mounted() {
console.log("vue2 中的生命周期 mounted");
},
beforeUpdate() {
console.log("vue2 中的生命周期 beforeUpdate");
},
updated() {
console.log("vue2 中的生命周期 updated");
},
// vue2中的 beforeDestroy与 destroyed已经改名 无法使用
beforeUnmount() {
console.log("vue2 中的生命周期 beforeDestroy(beforeUnmount)");
},
unmounted() {
console.log("vue2 中的生命周期 destroyed(unmounted)");
},
setup() {
console.log("vue3中的setup");
const name = ref("hhh");
const updateName = () => {
name.value += "6……6………6";
};
onBeforeMount(() => {
console.log("vue3 中的生命周期 onBeforeMount");
});
onMounted(() => {
console.log("vue3 中的生命周期 onMounted");
});
onBeforeUpdate(() => {
console.log("vue3 中的生命周期 onBeforeUpdate");
});
onUpdated(() => {
console.log("vue3 中的生命周期 onUpdated");
});
onBeforeUnmount(() => {
console.log("vue3 中的生命周期 onBeforeUnmount");
});
onUnmounted(() => {
console.log("vue3 中的生命周期 onUnmounted");
});
return {
name,
updateName,
};
},
});
</script>
运行起来的显示效果
进入页面 按f12 打开调试 刷新页面
可以看出vue3中
setup
执行在beforeCreate与created前面;
onBeforeMount
执行在beforeMount前面;
onMounted
执行在mounted前面;
点击 更新name
可以看出vue3中
onBeforeUpdate
执行在beforeUpdate前面;
onUpdated
执行在updated前面;
点击 切换child子组件的显示
可以看出vue3中
onBeforeUnmount
执行在beforeDestroy前面;
onUnmounted
执行在destroyed前面;
生命周期:在创建一个vue实例时,会经历一系列的初始化过程(Vue实例从创建到销毁的过程),这个过程就是vue的生命周期。
Vue提供给开发者的一系列的回调函数,方便我们添加自定义的逻辑,Vue的生命周期从创建到销毁,重要的节点挂载数据更新。
创建阶段 beforeCreate、created
挂载渲染页面阶段 beforeMount、mounted
更新阶段 beforeUpdate、updated
卸载阶段 beforeDestory、destoryed
1、单页面下生命周期顺序献上一波代码,看下各周期钩子函数的执行顺序:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue生命周期学习</title>
<script src="https://cdn.bootcss.com/vue/2.4.2/vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{message}}</h1>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Vue的生命周期'
},
beforeCreate: function() {
console.group('------beforeCreate创建前状态------');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message)
},
created: function() {
console.group('------created创建完毕状态------');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeMount: function() {
console.group('------beforeMount挂载前状态------');
console.log("%c%s", "color:red","el : " + (this.$el)); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
mounted: function() {
console.group('------mounted 挂载结束状态------');
console.log("%c%s", "color:red","el : " + this.$el); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeUpdate: function () {
console.group('beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el.innerHTML);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('updated 更新完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el.innerHTML);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
beforeDestroy: function () {
console.group('beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
destroyed: function () {
console.group('destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
}
})
</script>
</html>
(1)创建阶段:初始化事件,进行数据的观测
new Vue({}) 创建一个空的实例对象,这个对象上只有生命周期函数和一些默认事件
在beforeCreate时,$el和data都未初始化
created 执行,完成了对data的初始化,通过编译将 template 模板转换成渲染函数( render ) ,执行渲染函数就可以得到一个虚拟节点树(内存中)
先检查 template是否存在 如果存在模板编译成render函数,没有将外部html作为模板渲染。综合排名优先级:render函数选项 > template选项 > outer HTML.
(2)挂载阶段
为vue实例添加$el成员,替换挂载的DOM成员
其中在beforeMount时,初始化el和data,但el和data,但el和data,但el还是使用{{message}}进行占位
mounted执行时,将message的值进行渲染
(3)更新阶段:触发对应组件的重新渲染
data 被改变时触发生命周期函数 beforeUpdate 执行,data是最新的,页面还未更新(旧的页面)
根据最新的 data 重新渲染虚拟 DOM,并挂载到页面上,完成 Model 到 View 的更新
updated 执行,此时 data 和页面都是最新的
(4)销毁阶段
beforeDestroy钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed钩子函数在Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
2、父子、兄弟组件的生命周期顺序<template>
<div class="father">
<component-A class="son_A"></component-A>
<component-B class="son_B"></component-B>
</div>
</template>
// script部分同上代码,不多写了。
主要可以从以下几种情况分析:
(1)创建过程:
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
(2)组件的内部更新:
子组件的内部更新过程是:子beforeUpdate->子updated
同理父组件的内部更新过程也是:父beforeUpdate->父updated
(3)组件之间的更新:
当子组件使用emit修改父组件状态时,刚好这个状态又绑定在子组件的props上,更新过程是:父beforeUpdate->子beforeUpdate->子updated->父updated
(4)父子组件销毁:
父组件被销毁时子组件也同时被销毁,销毁的钩子过程是:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
父子组件完整的生命周期图如下所示:
从上图可以看出,在父兄子组件挂载前,各组件的实例已经初始化完成。
子组件挂载完成后,父组件还未挂载。所以组件数据回显的时候,在父组件mounted中获取api的数据,子组件的mounted是拿不到的。
仔细看看父子组件生命周期钩子的执行顺序,会发现created这个钩子是按照从外内顺序执行,所以回显场景的解决方案是:在created中发起请求获取数据,依次在子组件的created中会接收到这个数据。
Vue父子组件生命周期钩子的执行顺序遵循:从外到内,然后再从内到外,不管嵌套几层深,也遵循这个规律。
3、不同页面跳转时各页面生命周期的执行顺序跳转不同页面和part2是相同的原理,从第一个页面(index)跳转到下一个页面(secondIndex)时,回先初始化secondIndex,之后在执行index页面的销毁阶段,最后secondIndex挂载完成.
题外话:
在开发过程中,通过对整个生命周期的了解,就可以很清晰地知道可以在什么阶段做什么事,或者某一操作应该在什么阶段执行
例如在create中进行数据操作,在mounted中进行DOM完成后的操作,在destroyed进行事件解绑和功能注销
当然,对于组件间、不同页面跳转的生命周期顺序也应该更加了解,避免页面渲染数据错误或根本拿不到数据等情况
总结来说就是在合适的时机做对的事情,才能事半功倍嘛~
以上为个人经验,希望能给大家一个参考,也希望大家多多支持易知道(ezd.cc)。