vue2與vue3中生命周期執(zhí)行順序的區(qū)別說(shuō)明
vue2與vue3中生命周期執(zhí)行順序區(qū)別
生命周期比較
- vue2中執(zhí)行順序
beforeCreate=>created=>beforeMount=>mounted=>beforeUpdate=>updated=>beforeDestroy=>destroyed - vue3中執(zhí)行順序
setup=>onBeforeMount=>onMounted=>onBeforeUpdate=>onUpdated=>onBeforeUnmount=>onUnmounted
對(duì)應(yīng)關(guān)系
vue2->vue3
beforeCreate->setupcreated->setupbeforeMount->onBeforeMountmounted->onMountedbeforeUpdate->onBeforeUpdateupdated->onUpdatedbeforeDestroy->onBeforeUnmountdestroyed->onUnmounted
其中 vue3中的setup相當(dāng)于vue2中beforeCreate 與created 但是的執(zhí)行在beforeCreate 與created之前,所以setup無(wú)法使用 data 和 methods 中的數(shù)據(jù)和方法,即無(wú)法操作this,setup中的this等于 undefined,又因?yàn)閟etup中創(chuàng)建的變量與方法最后都要通過(guò)return返回出去,所以setup中的程序只能是同步的,而不能是異步,除非return 后面只接受一個(gè)異步對(duì)象,對(duì)象返回setup內(nèi)定義的變量與方法,然后父組件使用Suspense標(biāo)簽包裹異步組件;
vue3中 如果要使用vue2的beforeDestroy與destroyed需要把名稱(chēng)分別改為beforeUnmount,unmounted
如果vue3中同時(shí)使用了vue2的寫(xiě)法,vue3的寫(xiě)法會(huì)優(yōu)先執(zhí)行;
簡(jiǎn)單例子說(shuō)明
父組件App.vue
<template> ? <h1>App父級(jí)組件</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 子級(jí)組件</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已經(jīng)改名 無(wú)法使用
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>
運(yùn)行起來(lái)的顯示效果

進(jìn)入頁(yè)面 按f12 打開(kāi)調(diào)試 刷新頁(yè)面

可以看出vue3中
setup執(zhí)行在beforeCreate與created前面;onBeforeMount執(zhí)行在beforeMount前面;onMounted執(zhí)行在mounted前面;
點(diǎn)擊 更新name

可以看出vue3中
onBeforeUpdate執(zhí)行在beforeUpdate前面;onUpdated執(zhí)行在updated前面;- 點(diǎn)擊 切換child子組件的顯示

可以看出vue3中
onBeforeUnmount執(zhí)行在beforeDestroy前面;onUnmounted執(zhí)行在destroyed前面;
三種情況下的生命周期執(zhí)行順序
生命周期:在創(chuàng)建一個(gè)vue實(shí)例時(shí),會(huì)經(jīng)歷一系列的初始化過(guò)程(Vue實(shí)例從創(chuàng)建到銷(xiāo)毀的過(guò)程),這個(gè)過(guò)程就是vue的生命周期。
Vue提供給開(kāi)發(fā)者的一系列的回調(diào)函數(shù),方便我們添加自定義的邏輯,Vue的生命周期從創(chuàng)建到銷(xiāo)毀,重要的節(jié)點(diǎn)掛載數(shù)據(jù)更新。
- 創(chuàng)建階段 beforeCreate、created
- 掛載渲染頁(yè)面階段 beforeMount、mounted
- 更新階段 beforeUpdate、updated
- 卸載階段 beforeDestory、destoryed
1、單頁(yè)面下生命周期順序
獻(xiàn)上一波代碼,看下各周期鉤子函數(shù)的執(zhí)行順序:
<!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生命周期學(xué)習(xí)</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創(chuàng)建前狀態(tài)------');
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創(chuàng)建完畢狀態(tài)------');
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掛載前狀態(tài)------');
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 掛載結(jié)束狀態(tài)------');
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 更新前狀態(tài)===============》');
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 更新完成狀態(tài)===============》');
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 銷(xiāo)毀前狀態(tài)===============》');
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 銷(xiāo)毀完成狀態(tài)===============》');
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)創(chuàng)建階段:初始化事件,進(jìn)行數(shù)據(jù)的觀測(cè)
- new Vue({}) 創(chuàng)建一個(gè)空的實(shí)例對(duì)象,這個(gè)對(duì)象上只有生命周期函數(shù)和一些默認(rèn)事件
- 在beforeCreate時(shí),$el和data都未初始化
- created 執(zhí)行,完成了對(duì)data的初始化,通過(guò)編譯將 template 模板轉(zhuǎn)換成渲染函數(shù)( render ) ,執(zhí)行渲染函數(shù)就可以得到一個(gè)虛擬節(jié)點(diǎn)樹(shù)(內(nèi)存中)
- 先檢查 template是否存在 如果存在模板編譯成render函數(shù),沒(méi)有將外部html作為模板渲染。綜合排名優(yōu)先級(jí):render函數(shù)選項(xiàng) > template選項(xiàng) > outer HTML.

(2)掛載階段
- 為vue實(shí)例添加$el成員,替換掛載的DOM成員
- 其中在beforeMount時(shí),初始化el和data,但el和data,但el和data,但el還是使用{{message}}進(jìn)行占位
- mounted執(zhí)行時(shí),將message的值進(jìn)行渲染

(3)更新階段:觸發(fā)對(duì)應(yīng)組件的重新渲染
- data 被改變時(shí)觸發(fā)生命周期函數(shù) beforeUpdate 執(zhí)行,data是最新的,頁(yè)面還未更新(舊的頁(yè)面)
- 根據(jù)最新的 data 重新渲染虛擬 DOM,并掛載到頁(yè)面上,完成 Model 到 View 的更新
- updated 執(zhí)行,此時(shí) data 和頁(yè)面都是最新的

(4)銷(xiāo)毀階段
- beforeDestroy鉤子函數(shù)在實(shí)例銷(xiāo)毀之前調(diào)用。在這一步,實(shí)例仍然完全可用。
- destroyed鉤子函數(shù)在Vue 實(shí)例銷(xiāo)毀后調(diào)用。調(diào)用后,Vue 實(shí)例指示的所有東西都會(huì)解綁定,所有的事件監(jiān)聽(tīng)器會(huì)被移除,所有的子實(shí)例也會(huì)被銷(xiāo)毀。
2、父子、兄弟組件的生命周期順序
<template> <div class="father"> <component-A class="son_A"></component-A> <component-B class="son_B"></component-B> </div> </template> // script部分同上代碼,不多寫(xiě)了。
主要可以從以下幾種情況分析:
(1)創(chuàng)建過(guò)程:
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

(2)組件的內(nèi)部更新:

子組件的內(nèi)部更新過(guò)程是:子beforeUpdate->子updated
同理父組件的內(nèi)部更新過(guò)程也是:父beforeUpdate->父updated
(3)組件之間的更新:
當(dāng)子組件使用emit修改父組件狀態(tài)時(shí),剛好這個(gè)狀態(tài)又綁定在子組件的props上,更新過(guò)程是:父beforeUpdate->子beforeUpdate->子updated->父updated

(4)父子組件銷(xiāo)毀:
父組件被銷(xiāo)毀時(shí)子組件也同時(shí)被銷(xiāo)毀,銷(xiāo)毀的鉤子過(guò)程是:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

父子組件完整的生命周期圖如下所示:

- 從上圖可以看出,在父兄子組件掛載前,各組件的實(shí)例已經(jīng)初始化完成。
- 子組件掛載完成后,父組件還未掛載。所以組件數(shù)據(jù)回顯的時(shí)候,在父組件mounted中獲取api的數(shù)據(jù),子組件的mounted是拿不到的。
- 仔細(xì)看看父子組件生命周期鉤子的執(zhí)行順序,會(huì)發(fā)現(xiàn)created這個(gè)鉤子是按照從外內(nèi)順序執(zhí)行,所以回顯場(chǎng)景的解決方案是:在created中發(fā)起請(qǐng)求獲取數(shù)據(jù),依次在子組件的created中會(huì)接收到這個(gè)數(shù)據(jù)。
- Vue父子組件生命周期鉤子的執(zhí)行順序遵循:從外到內(nèi),然后再?gòu)膬?nèi)到外,不管嵌套幾層深,也遵循這個(gè)規(guī)律。
3、不同頁(yè)面跳轉(zhuǎn)時(shí)各頁(yè)面生命周期的執(zhí)行順序
跳轉(zhuǎn)不同頁(yè)面和part2是相同的原理,從第一個(gè)頁(yè)面(index)跳轉(zhuǎn)到下一個(gè)頁(yè)面(secondIndex)時(shí),回先初始化secondIndex,之后在執(zhí)行index頁(yè)面的銷(xiāo)毀階段,最后secondIndex掛載完成.


題外話:
在開(kāi)發(fā)過(guò)程中,通過(guò)對(duì)整個(gè)生命周期的了解,就可以很清晰地知道可以在什么階段做什么事,或者某一操作應(yīng)該在什么階段執(zhí)行
例如在create中進(jìn)行數(shù)據(jù)操作,在mounted中進(jìn)行DOM完成后的操作,在destroyed進(jìn)行事件解綁和功能注銷(xiāo)
當(dāng)然,對(duì)于組件間、不同頁(yè)面跳轉(zhuǎn)的生命周期順序也應(yīng)該更加了解,避免頁(yè)面渲染數(shù)據(jù)錯(cuò)誤或根本拿不到數(shù)據(jù)等情況
總結(jié)來(lái)說(shuō)就是在合適的時(shí)機(jī)做對(duì)的事情,才能事半功倍嘛~
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
element-ui vue input輸入框自動(dòng)獲取焦點(diǎn)聚焦方式
這篇文章主要介紹了element-ui vue input輸入框自動(dòng)獲取焦點(diǎn)聚焦方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
Vue.js實(shí)現(xiàn)一個(gè)SPA登錄頁(yè)面的過(guò)程【推薦】
本篇文章主要介紹了Vue.js寫(xiě)一個(gè)SPA登錄頁(yè)面過(guò)程的相關(guān)知識(shí),具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04
Vue2.0結(jié)合webuploader實(shí)現(xiàn)文件分片上傳功能
這篇文章主要介紹了Vue2.0結(jié)合webuploader實(shí)現(xiàn)文件分片上傳功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-03-03
使用vue/cli出現(xiàn)defineConfig?is?not?function錯(cuò)誤解決辦法
這篇文章主要給大家介紹了關(guān)于使用vue/cli出現(xiàn)defineConfig?is?not?function錯(cuò)誤的解決辦法,當(dāng)我們?cè)谧龃虬渲玫臅r(shí)候,出現(xiàn)了這個(gè)錯(cuò)誤,需要的朋友可以參考下2023-11-11
玩轉(zhuǎn)vue的slot內(nèi)容分發(fā)
這篇文章主要介紹了玩轉(zhuǎn)vue的slot內(nèi)容分發(fā),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
Vue2.x如何解決Element組件el-tooltip滾動(dòng)時(shí)錯(cuò)位不消失的問(wèn)題
這篇文章主要介紹了Vue2.x如何解決Element組件el-tooltip滾動(dòng)時(shí)錯(cuò)位不消失的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
vue中tab選項(xiàng)卡的實(shí)現(xiàn)思路
今天給大家分享vue中tab 選項(xiàng)卡的一些套路,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-11-11
elementui源碼學(xué)習(xí)之仿寫(xiě)一個(gè)el-divider組件
這篇文章主要為大家介紹了elementui源碼學(xué)習(xí)之仿寫(xiě)一個(gè)el-divider組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Vue3 openlayers加載瓦片地圖并手動(dòng)標(biāo)記坐標(biāo)點(diǎn)功能
這篇文章主要介紹了 Vue3 openlayers加載瓦片地圖并手動(dòng)標(biāo)記坐標(biāo)點(diǎn)功能,我們這里用vue/cli創(chuàng)建,我用的node版本是18.12.1,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04

