使用過 Vue 的你們,對於生命週期必定都很熟悉,在官方文檔一開始,就給咱們介紹了 Vue 的生命週期有哪些,是怎麼樣的順序。這個難不倒你們。html
但若是是問當組件嵌套時,父子組件的生命週期函數觸發的順序是什麼樣的?你是否是會有一絲絲不肯定呢?vue
若是有的話,就讓咱們一塊兒動動手來確認下這個簡單的問題吧。web
首先,一個 Vue 實例/組件的生命週期中的 8 個關鍵階段:app
beforeCreate
:在實例初始化以後,數據觀測 (data observer) 和 event/watcher 事件配置以前被調用。
created
:在實例建立完成後被當即調用。在這一步,實例已完成數據觀測 (data observer),屬性和方法的運算,watch/event 事件回調。
beforeMount
:在掛載開始以前被調用:相關的
render
函數首次被調用。
mounted
:實例被掛載後調用,這時
el
被新建立的
vm.$el
替換了。
beforeUpdate
:數據更新時調用,發生在虛擬 DOM 打補丁以前。
updated
:虛擬 DOM 從新渲染和打補丁以後。
beforeDestory
:實例銷燬以前調用。在這一步,實例仍然徹底可用。
destoryed
:實例銷燬後調用。對應 Vue 實例的全部指令都被解綁,全部的事件監聽器被移除,全部的子實例也都被銷燬。
咱們也能夠再看一下 官網的生命週期圖示[1]回想一下。異步
針對上面的 8 個生命週期,咱們能夠將其分爲三個階段,分別爲:建立掛載階段、更新階段和銷燬階段。async
下面就讓咱們依次來確認下當組件嵌套時,這三個階段生命週期的觸發順序是怎麼樣的?編輯器
示例代碼:codesandbox.io/s/qiantaozu…ide
若是你仔細閱讀各階段的描述,你應該能想到當組件嵌套時,子組件的建立掛載是在父組件掛載的時候才觸發的。下面咱們來確認下。函數
打開示例代碼,默認狀況下是沒有渲染組件的。這個時候咱們點擊:勾選顯示組件,你會看到以下頁面,父子組件會渲染出來。flex
此時,能夠看到console
中輸出了父子組件的觸發順序。
順序以下:
能夠看到子組件的建立掛載階段確實是在父組件的掛載階段完成的,開始於父組件的beforeMount
以後,結束於父組件的mounted
以前。
一樣的,更新階段比較簡單,有了上面的經驗,基本能夠肯定子組件的更新過程是在父組件的beforeUpdate
和updated
之間。
修改頁面中的父組件的名稱,能夠看到輸出的生命週期觸發順序確實如預期,以下:
說到這裏,銷燬階段應該沒啥好說的了,子組件的銷燬是在父組件的beforeDestroy
和destroyed
之間完成的。
點擊示例代碼,取消勾選顯示組件,能夠看到以下順序:
如今讓咱們在官方的生命週期圖示上作一點拓展,加上組件嵌套時的生命週期。以下圖所示:
好了,今天要分享的內容到這裏就結束了。
哈哈,開個玩笑,顯然不會這麼水,否則歪馬本身都看不下去。
下面咱們繼續。上面咱們經過簡單直觀的方式確認了下組件嵌套時,生命週期函數觸發的順序是什麼樣的。然而縝密的你可能已經發現了,上面的示例都是以同步組件爲例的。當組件爲異步組件時會發生什麼變化呢?
前面,歪馬留了一手,官方文檔上有指出以下內容:「mounted
不會保證全部的子組件也都一塊兒被掛載」、「updated
不會保證全部的子組件也都一塊兒被重繪。」。
之因此官網會給出如此說明,是由於當組件爲異步組件時,生命週期的觸發順序會和上面多有不一樣。
話很少說,咱們先把組件改爲異步的,看看結果。從 demo 中找到src/components/OuterBox.vue
,將InnerBox
改成異步加載。如:
// 異步組件
InnerBox: () => import("./InnerBox")
複製代碼
而後咱們從新勾選顯示頁面,能夠發現,當子組件爲異步,子組件的建立掛載階段發生在父組件的beforeUpdate
和updated
之間。
咱們稍微翻一下 Vue 的源碼,能夠看到當組件是異步組件時,會執行異步組件的工廠函數,在組件加載完成以後,會強制更新全部包含該組件的父組件。
異步函數的工廠函數就是上面的
() => import("./InnerBox")
,官方文檔指出,只要是一個返回值是 Promise 的函數就行。返回值也能夠是更復雜的帶有加載狀態的對象,能夠參見文檔。
// ...
var forceRender = function (renderCompleted) {
for (var i = 0, l = owners.length; i < l; i++) {
// 依次強制更新父組件
(owners[i]).$forceUpdate();
}
};
var resolve = once(function (res) {
factory.resolved = ensureCtor(res, baseCtor);
// 若是是異步組件,則在resolve時強制更新父組件。
if (!sync) {
forceRender(true);
} else {
owners.length = 0;
}
});
var reject = once(function (reason) {//...});
// 執行異步組件的工廠函數
var res = factory(resolve, reject);
複製代碼
父組件更新時同理,若是存在新的異步加載組件,則不會等待。
好了,今天要分享的內容就是這麼簡單,就是想動動手確認下組件嵌套時,父子組件生命週期的執行順序是什麼。
生命週期圖示: https://cn.vuejs.org/v2/guide/instance.html#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%9B%BE%E7%A4%BA
本文使用 mdnice 排版