關於Vue.js2.0生命週期的研究與理解

寫在前面:進行一些項目實踐的時候,總會涉及到關於生命週期鉤子或多或少的使用。所以以爲有必要單獨梳理一下相關的知識點,若有理解錯誤的地方懇請告知修改。html

整體感知

首先貼一張Vue文檔給出的生命週期圖示,並添加了一些註釋
lifecycle.fw.png
Vue2.0的生命週期鉤子一共有10個,一樣結合官方文檔做出了下表vue

生命週期鉤子 詳細
beforeCreate 在實例初始化以後,數據觀測(data observer) 和 event/watcher 事件配置以前被調用。
created 實例已經建立完成以後被調用。在這一步,實例已完成如下的配置:數據觀測(data observer),屬性和方法的運算, watch/event 事件回調。然而,掛載階段還沒開始,$el 屬性目前不可見。
beforeMount 在掛載開始以前被調用:相關的 render 函數首次被調用。
mounted el 被新建立的 vm.$el 替換,並掛載到實例上去以後調用該鉤子。若是 root 實例掛載了一個文檔內元素,當 mounted 被調用時 vm.$el 也在文檔內。
beforeUpdate 數據更新時調用,發生在虛擬 DOM 從新渲染和打補丁以前。你能夠在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。
updated 因爲數據更改致使的虛擬 DOM 從新渲染和打補丁,在這以後會調用該鉤子。當這個鉤子被調用時,組件 DOM 已經更新,因此你如今能夠執行依賴於 DOM 的操做。
activated keep-alive 組件激活時調用。
deactivated keep-alive 組件停用時調用。
beforeDestroy 實例銷燬以前調用。在這一步,實例仍然徹底可用。
destroyed Vue 實例銷燬後調用。調用後,Vue 實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬。

(除了beforeCreate和created鉤子以外,其餘鉤子均在服務器端渲染期間不被調用。)ajax

實際操做

咱們來可視化的觀察一下生命週期鉤子函數執行時狀態變化的狀況vue-router

測試過程基於如下代碼執行,引入vue.js後可直接執行瀏覽器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="./vue.js"></script>
</head>
<body>
<div id="app">
    <p>{{message}}</p>
    <keep-alive>
        <my-components msg="hello" v-if="show"></my-components>
    </keep-alive>
</div>
</body>
<script>
    var child = {
        template: '<div>from child: {{msg}}</div>',
        props: ['msg'],
        data: function () {
            return {
                childMsg: 'child'
            };
        },
        deactivated: function () {
            console.log('component deactivated!');
        },
        activated: function () {
            console.log('component activated');
        }
    };
    var app = new Vue({
        el: '#app',
        data: function () {
            return {
                message: 'father',
                show: true
            };
        },
        beforeCreate: function () {
            console.group('beforeCreate 建立前狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(state);
        },
        created: function () {
            console.group('created 建立完畢狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(state);
        },
        beforeMount: function () {
            console.group('beforeMount 掛載前狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
        },
        mounted: function () {
            console.group('mounted 掛載結束狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
            // this.message = 'change';
        },
        beforeUpdate: function () {
            console.group('beforeUpdate 更新前狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
            // this.message = 'change2';
        },
        updated: function () {
            console.group('updated 更新完成狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
        },
        beforeDestroy: function () {
            console.group('beforeDestroy 銷燬前狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
        },
        destroyed: function () {
            console.group('destroyed 銷燬完成狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
        },
        components: {
            'my-components': child
        }
    });
</script>
</html>

首先來梳理一下結構:
1.咱們建立了一個Vue根實例命名爲app,將其掛載到頁面id爲app的dom元素上。
2.局部註冊的一個組件child並在根實例中將其註冊使其能夠在根實例的做用域中使用。
3.將子組件用<keep-alive> 包裹,爲接下來的測試做準備。
在谷歌瀏覽器打開開發者工具,開始測試!緩存

create 和 mounted 相關

測試效果圖以下:
test1.jpg
根據測試結果,能夠看出服務器

1.beforeCreate執行時:data和el均未初始化,值爲undefinedapp

2.created執行時:Vue 實例觀察的數據對象data已經配置好,已經能夠獲得app.message的值,但Vue 實例使用的根 DOM 元素el還未初始化
3.beforeMount執行時:data和el均已經初始化,但從{{message}}等現象能夠看出此時el並無渲染進數據,el的值爲「虛擬」的元素節點
4.mounted執行時:此時el已經渲染完成並掛載到實例上dom

activated 和 destroyed相關

  在前面的測試圖中,咱們發現了activated週期鉤子已經被觸發,這是由於子組件my-components被<keep-alive> 包裹,隨el的掛載觸發。
  如今咱們將此組件停用進行測試:因爲子組件具備一個v-if指令v-if="show",所以咱們能夠經過將show的值置爲false將其銷燬。
  控制檯輸入 app.show = false;測試結果以下:
test2.jpg函數

因爲在這裏咱們修改了data的值,因此會觸發beforeUpdate和updated鉤子,這裏先不討論這一組鉤子,咱們看到deactivated鉤子已經觸發,表示<keep-alive>已經停用,符合預期結果。

  

如今咱們對Vue實例進行銷燬,調用app.$destroy()方法便可將其銷燬,控制檯測試以下:
test3.jpg

咱們發現實例依然存在,可是此時變化已經發生在了其餘地方,根據官方文檔描述:Vue 實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬。

繼續測試,如今修改 data中的數據查看結果,以下:
test4.jpg

這裏咱們將data中的message屬性改爲了'world',發現dom並無進行相應的響應,這證明了以前的說法。一樣,若是你在子組件也加入destroyed鉤子,發現該鉤子也會被觸發,這也證實了子實例也會被一塊兒銷燬。這裏的銷燬並不指代'抹去',而是表示'解綁'。

updated相關

beforeUpdate和updated是最後一對週期鉤子了。
爲了能看出測試的具體效果,咱們須要在原來的代碼上添加兩行代碼:

在c鉤子和updated鉤子中分別加上

console.log('beforeUpdate == ' + document.getElementsByTagName('p')[0].innerHTML);

控制檯輸入app.message = 'abc';效果以下:
test5.jpg

咱們發現beforeUpdate和updated觸發時,el中的數據都已經渲染完成,但根據beforeUpdate == father而updated == abc可知,只有updated鉤子被調用時候,組件dom才被更新。

一些應用的想法

  1. 在created鉤子中能夠對data數據進行操做,這個時候能夠進行ajax請求將返回的數據賦給data

  2. 在mounted鉤子對掛載的dom進行操做

  3. 在使用vue-router時有時須要使用<keep-alive></keep-alive>來緩存組件狀態,這個時候created鉤子就不會被重複調用了,若是咱們的子組件須要在每次加載的時候進行某些操做,可使用activated鉤子觸發。

結尾

到這裏已經總結完成了,感受只有理解的生命週期鉤子的使用,才能更好配合其餘方法事件使用。若是您發現錯誤的地方,請告訴我及時修改,謝謝!

相關文章
相關標籤/搜索