Vue組件嵌套時生命週期函數觸發順序是什麼?

使用過 Vue 的你們,對於生命週期必定都很熟悉,在官方文檔一開始,就給咱們介紹了 Vue 的生命週期有哪些,是怎麼樣的順序。這個難不倒你們。html

但若是是問當組件嵌套時,父子組件的生命週期函數觸發的順序是什麼樣的?你是否是會有一絲絲不肯定呢?vue

若是有的話,就讓咱們一塊兒動動手來確認下這個簡單的問題吧。markdown

首先,一個 Vue 實例/組件的生命週期中的 8 個關鍵階段:異步

  1. beforeCreate:在實例初始化以後,數據觀測 (data observer) 和 event/watcher 事件配置以前被調用。
  2. created:在實例建立完成後被當即調用。在這一步,實例已完成數據觀測 (data observer),屬性和方法的運算,watch/event 事件回調。
  3. beforeMount:在掛載開始以前被調用:相關的 render 函數首次被調用。
  4. mounted:實例被掛載後調用,這時 el 被新建立的 vm.$el 替換了。
  5. beforeUpdate:數據更新時調用,發生在虛擬 DOM 打補丁以前。
  6. updated:虛擬 DOM 從新渲染和打補丁以後。
  7. beforeDestory:實例銷燬以前調用。在這一步,實例仍然徹底可用。
  8. destoryed:實例銷燬後調用。對應 Vue 實例的全部指令都被解綁,全部的事件監聽器被移除,全部的子實例也都被銷燬。

咱們也能夠再看一下 官網的生命週期圖示[1]回想一下。async

來源:https://cn.vuejs.org/
來源:https://cn.vuejs.org/

針對上面的 8 個生命週期,咱們能夠將其分爲三個階段,分別爲:建立掛載階段、更新階段和銷燬階段。ide

下面就讓咱們依次來確認下當組件嵌套時,這三個階段生命週期的觸發順序是怎麼樣的?函數

示例代碼:codesandbox.io/s/qiantaozu…oop

1. 建立掛載階段

若是你仔細閱讀各階段的描述,你應該能想到當組件嵌套時,子組件的建立掛載是在父組件掛載的時候才觸發的。下面咱們來確認下。ui

打開示例代碼,默認狀況下是沒有渲染組件的。這個時候咱們點擊:勾選顯示組件,你會看到以下頁面,父子組件會渲染出來。spa

此時,能夠看到console中輸出了父子組件的觸發順序。

順序以下:

能夠看到子組件的建立掛載階段確實是在父組件的掛載階段完成的,開始於父組件的beforeMount以後,結束於父組件的mounted以前。

2. 更新階段

一樣的,更新階段比較簡單,有了上面的經驗,基本能夠肯定子組件的更新過程是在父組件的beforeUpdateupdated之間。

修改頁面中的父組件的名稱,能夠看到輸出的生命週期觸發順序確實如預期,以下:

3. 銷燬階段

說到這裏,銷燬階段應該沒啥好說的了,子組件的銷燬是在父組件的beforeDestroydestroyed之間完成的。

點擊示例代碼,取消勾選顯示組件,能夠看到以下順序:

如今讓咱們在官方的生命週期圖示上作一點拓展,加上組件嵌套時的生命週期。以下圖所示:

組件嵌套時的生命週期圖示
組件嵌套時的生命週期圖示

好了,今天要分享的內容到這裏就結束了。


哈哈,開個玩笑,顯然不會這麼水,否則歪馬本身都看不下去。

下面咱們繼續。上面咱們經過簡單直觀的方式確認了下組件嵌套時,生命週期函數觸發的順序是什麼樣的。然而縝密的你可能已經發現了,上面的示例都是以同步組件爲例的。當組件爲異步組件時會發生什麼變化呢?

3. 當組件是異步組件時

前面,歪馬留了一手,官方文檔上有指出以下內容:「mounted 不會保證全部的子組件也都一塊兒被掛載」、「updated 不會保證全部的子組件也都一塊兒被重繪。」。

之因此官網會給出如此說明,是由於當組件爲異步組件時,生命週期的觸發順序會和上面多有不一樣。

異步子組件的建立和掛載

話很少說,咱們先把組件改爲異步的,看看結果。從 demo 中找到src/components/OuterBox.vue,將InnerBox改成異步加載。如:

// 異步組件
InnerBox: () => import("./InnerBox")
複製代碼

而後咱們從新勾選顯示頁面,能夠發現,當子組件爲異步,子組件的建立掛載階段發生在父組件的beforeUpdateupdated之間。

咱們稍微翻一下 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);
複製代碼

父組件更新時同理,若是存在新的異步加載組件,則不會等待。

好了,今天要分享的內容就是這麼簡單,就是想動動手確認下組件嵌套時,父子組件生命週期的執行順序是什麼。

參考資料

[1]

生命週期圖示: 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 排版

相關文章
相關標籤/搜索