iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 21
1
Modern Web

學習 vue 30天系列 第 21

Vue 21 Vue.js 的生命週期 - 從出生到死亡以及長生不老的方法

Vue生命週期簡介

每個 Vue instance 都要經過一系列初始化步驟。當創建它時,從設置數據觀察(data observation)到編譯模板(compiling template),到將 instance 掛載(mount)到 DOM,最後到在數據更改期間更新 DOM。這個過程稱為 Vue instance 的生命週期,在創建到消滅 DOM 的過程中,Vue instance 中有默認運行一些 function。這些 Vue 組件以被創建和存在 Vue 的 instance 裡面,這些功能稱為生命週期鉤子(Hooks)。

圖上看到的白底紅框的方塊這些都是 Hooks,每個 Hooks 都是 function,我們可以透過這些 function 內設定一些我們要的行為,像是 AJAX 取資料的觸發時機點。

除了以上八個 Hooks 還有 activated hookdeactivated hook 可以使用,這些是在不同的情況下使用。

實體生命週期

生命週期主要可以分 4 個階段以及額外的 1 個階段(activated 和 deactivated),我們先著重在 4 的部分,最後在補充說明 1 的內容。

第一階段:Creation 初始建置

Creation 階段是組件中運行的第一個 Hook 函式,與其他階段不同,它是在伺服器端渲染期間運行。

因此,若需要在客戶端渲染和伺服器渲染期間於元件當中設置事件,須於此階段進行設定。

1. beforeCreate

什麼事都還沒做,只跟大家說我要開始囉!

這是最一開始的 Hook,在 vue instance 被初始化後同步呼叫。

需要知道的是,在此 Hook 時 data observation 和 event/watcher 等等都還沒建立。

2. created

我所有屬性都已經綁定囉,但是 $el 還沒建立,DOM 也還沒生成。

在此時期的 Hook 已經被初始化,在 vue instance 被建立後同步呼叫。

在此時期,包含 data observation, computed 屬性, methods, watch/event callbacks 等項目都已設定完成,但 mount 還沒開始所以 $el 屬性還沒建立好,也就是DOM 還沒生成可以讓我們操控。

第二階段:Mounting 資料掛載

接續上一個階段,首先他會先判斷是否有無 $el 屬性,若沒有則會嘗試另一種掛載方式(使用 $mount 掛載 el)。

再來會判斷是否有 $template 屬性 ,若有則直接使用 render function ,反之則使用 $el teamplate 進行模板編譯。

判斷完後進入正式進入 Mounting 階段。

3. beforeMount

我要開始產 virtual DOM 囉!

這是要開始產生 DOM 但尚未產生出 DOM 的時期(執行元素掛載之前),模板(template)和 scoped styles 都已經被編譯在這個時期,但你任然不能操控 DOM 元素,代表 $el 尚未被建立。

簡單來說就是:在這時期還沒有模板全部掛載到 HTML 的 DOM 上。

4. mounted

我已經努力的產生出 DOM 了!

元素已掛載, $el 被建立,這時就可以進行一些 HTML 的操作,這也是最常使用的生命週期 hook 。

假設有載入 Jqury 要到這個時期才能對 DOM 進行操作。

※ mounted 不保證此時所有的子 components 也都完成掛載,所以如果希望大家都掛載完成的話可以使用 vm.$nextTick 來替換 mounted,如以下所示

mounted: function () {
  this.$nextTick(function () {
    // Code that will run only after the
    // entire view has been rendered
  })
}

第三階段:Updating 資料改變,重新渲染畫面

當元件的資料屬性發生變動,或其他因素導致畫面需要重新渲染時,則會調用 Updating 刷新網頁內容。

5. beforeUpdated

data 收到更新異動,我會在更新前調用它,但還不會渲染畫面!

這是 mounted hook 之後調用的生命週期 Hook,每當需要更新 DOM 的 data 時都會調用這個 Hook。

當資料改變被呼叫使用,還不會渲染 View,data 在變更的時候這個階段非常適合任何邏輯處理。

6. updated

DOM已經完成更新啦!

當資料更新完成,則驅動 DOM 元素重新渲染畫面 View。

這裡可以執行 DOM 相關的操作,但是不建議在這個 Hook 中更改狀態,因為 Vue 已經為此提供了專門的方法來做這項事情(computed 和 watch)。

第四階段:Destruction 元件銷毀

當呼叫 destroy 函式時,則會執行銷毀的動作,將原始的元件從 DOM 元素中移除。

※大多數的狀況不會調用到beforeDestroy和destroyed這兩個hook,最好使用v-if & v-for以data控制component的生命週期。

7. beforeDestroy

Vue instance被銷毀前調用,這時候大家功能都還能使用!

instance 和所有功能仍然完好無損,在這個時期都還能使用,您可以進行資源管理、刪除變量和清理組件。

8. destroyed

Vue instance 所有的東西都會解除綁定,event listener也會被移除

這是 Vue 生命週期的最後一個時期,在這個時期,所有的DOM 元素綁定被解除、移除偵聽事件、Vue child 實例也被一併銷毀。

第 4+1 階段:activating 保存資料,不銷毀

上面 4 個階段是我們常見的生命週期,那還有 1 個階段則是 activated hookdeactivated hook ,那它可以用來取代 Destruction 銷毀。

要避開 Destruction 階段並進入這個階段,需要搭配 HTML 的標籤 <keep-alive>,其特性是可以維持資料狀態,只會有 activated hook 與 deactivated hook 的情況產生,則不觸發 destroyed hook 。

當我們需要保留狀態的時候用 <keep-alive> 這個標籤,像是頁籤切換時可以使用,並維持各頁籤的生命週期。當我們重新的進入某頁籤時週期的 Creation 和 Mounting 階段都不會執行,而是直接進到 deactivated 這個時期。

<keep-alive> 包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。和<transition> 相似,<keep-alive> 是一個抽象組件:它自身不會渲染一個DOM元素,也不會出現在父組件鏈中。

生命週期的範例

Hooks:

<script>
    const Child = {
        template: '#childarea',
        data: function() {
            return {
                text: 'Vue data 資料狀態'
            }
        },
        beforeCreate() {
            console.log(`beforeCreate! ${this.text}`);
        },
        created() {
            alert(`created! ${this.text}`);
        },
        beforeMount() {
            alert(`beforeMount! ${this.text}`);
        },
        mounted() {
            alert(`mounted! ${this.text}`);
        },
        updated() {
            console.log(`updated! ${this.text}`);
        },
        activated() {
            alert(`activated! ${this.text}`);
        },
        deactivated() {
            alert(`deactivated! ${this.text}`);
        },
        beforeDestroy() {
            console.log(`beforeDestroy! ${this.text}`);
        },
        destroyed() {
            console.log(`destroyed! ${this.text}`);
        }
    };

    new Vue({
        el: '#app',
        data() {
            return {
                isShowing: false
            }
        },
        methods: {
            toggleShow() {
                this.isShowing = !this.isShowing;
            }
        },
        components: {
            appChild: Child
        }
    });
</script>

<keep-alive>

在沒有 <keep-alive> 這個標籤的時候,生命週期走完按鈕隱藏 textbox,然後再按一次按鈕,vue 會產生全新的 textbox:

<div id="app" class="text-center">
    <button @click="toggleShow" class="btn btn-primary">
      <span v-if="isShowing">Hide child</span>
      <span v-else>Show child</span>
    </button>
    <hr>
    <app-child v-if="isShowing"></app-child>
</div>

<script type="text/x-template" id="childarea">
    <div>
        <h4>Hello! {{ text }}</h4>
        <input type="text" class="form-control" v-model="text">
    </div>
</script>

<keep-alive>

<div id="app" class="text-center">
    <button @click="toggleShow" class="btn btn-primary">
      <span v-if="isShowing">Hide child</span>
      <span v-else>Show child</span>
    </button>
    <hr>
    <keep-alive>
        <app-child v-if="isShowing"></app-child>
    </keep-alive>
</div>

<script type="text/x-template" id="childarea">
    <div>
        <h4>Hello! {{ text }}</h4>
        <input type="text" class="form-control" v-model="text">
    </div>
</script>

資料來源


上一篇
Vue 20 進階模板語法介紹 (6) - 表單細節操作 - v-on 的頁面操作細節
下一篇
Vue 22 Component - 元件建立與註冊
系列文
學習 vue 30天30

尚未有邦友留言

立即登入留言