vue實例的常用選項(二)-生命週期函數

說到生命週期函數,就要來先談談生命週期,一個Vue實例從開始創建、初始化數據、編譯模板、掛載Dom、渲染→更新→渲染、銷燬等一系列過程,我們稱之爲Vue的生命週期
更通俗的說實例從被創建出來、運行、最後被銷燬所要經歷的一系列過程,就是生命週期。

在Vue生命週期的不同階段,內部會自動執行一些稱爲生命週期鉤子的函數,也稱之爲生命週期函數,也叫生命週期鉤子,生命週期事件。

這些生命週期鉤子可以在Vue的選項中配置,如下:

<div id="app">
  <input type="text" v-model="message">
  <button v-on:click="handleDestroy">銷燬</button>
  <p>{{message}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      message: 'Hello world',
    },
    methods: {
      handleDestroy() {
        this.$destroy();
      }
    },
    beforeCreate() {
      console.groupCollapsed("%c%s", "color:red", '1、實例創建之前: beforeCreate');
      console.log("$el:", this.$el,);
      console.log("$data:", this.$data);
      console.groupEnd();
    },
    created() {
      console.groupCollapsed("%c%s", "color:red", '2、實例創建完畢: created');
      console.log("$el:", this.$el);
      console.log("$data:", JSON.stringify(this.$data));
      console.groupEnd();
    },
    beforeMount() {
      console.groupCollapsed("%c%s", "color:red", '3、實例掛載之前: beforeMount');
      console.log("$el:", this.$el.innerHTML);
      console.log("$data:", JSON.stringify(this.$data));
      console.groupEnd();
    },
    mounted() {
      console.groupCollapsed("%c%s", "color:red", '4、實例掛載完畢: mounted');
      console.log("$el:", this.$el.innerHTML);
      console.log("$data:", JSON.stringify(this.$data));
      console.groupEnd();
    },
    beforeUpdate() {
      console.groupCollapsed("%c%s", "color:red", '5、實例更新之前: beforeUpdate');
      console.log("$el:", this.$el.innerHTML);
      console.log("$data:", JSON.stringify(this.$data));
      console.groupEnd();
    },
    updated() {
      console.groupCollapsed("%c%s", "color:red", '6、實例更新完畢:updated');
      console.log("$el:", this.$el.innerHTML);
      console.log("$data:", JSON.stringify(this.$data));
      console.groupEnd();
    },
    beforeDestroy() {
      console.groupCollapsed("%c%s", "color:red", '7、實例銷燬之前:beforeDestroy');
      console.log("$el:", this.$el.innerHTML);
      console.log("$data:", JSON.stringify(this.$data));
      console.groupEnd();
    },
    destroyed() {
      console.groupCollapsed("%c%s", "color:red", '8、實例銷燬完畢:destroyed');
      console.log("$el:", this.$el.innerHTML);
      console.log("$data:", JSON.stringify(this.$data));
      console.groupEnd();
    }
  });
</script>

上面的例子中,如果在生命週期的鉤子函數中打斷點觀察調用棧和作用域,更容易理解Vue的生命週期,在生命週期鉤子中我們看到Vue內部執行了很多方法,其結果是實例的this在不斷的變化。


生命週期的三個階段

一、創建階段

1.初始化事件和生命週期

實例、組件通過new Vue() 創建出來之後會初始化事件和生命週期
完成後,就會執行beforeCreate鉤子函數,這個時候,數據還沒有掛載,無法訪問到數據和真實的dom。
在這裏插入圖片描述

2. 初始化注入和校驗

實例完成數據觀測 (data observer), 屬性和方法的運算,watch/event 事件回調。但掛載階段還沒開始,$el 屬性目前不可見。
完成後,就會執行created鉤子函數,created函數是最早能夠調用data和methods數據的地方,更改數據不會觸發其他的鉤子函數,一般可以在這裏獲取初始數據。
在這裏插入圖片描述

3. 找實例或者組件對應的模板,編譯模板爲虛擬Dom放入到render函數中準備渲染

① 判斷實例裏是否有el選項

  • 存在el,實例將立即進入編譯過程;
  • 不存在el,需要顯式調用 vm.$mount() 手動開啓編譯。

② 判斷實例裏是否有template選項

  • 沒有,將el掛載點的HTML作爲template進行頁面渲染;
  • 有,使用實例裏面的template進行頁面渲染

完成後,就會執行beforeMount鉤子函數,這個函數中虛擬Dom已經創建完成,準備渲染,在這裏也可以更改數據,不會觸發數據更新鉤子。
在這裏插入圖片描述
5. 開始render,渲染出真實dom
完成後,就會執行mounted鉤子函數,這個時候,組件已經出現在頁面中,數據、真實dom都已經處理好了,事件都已經掛載好了。
在這裏插入圖片描述

二、運行階段

  1. 如果組件或實例的數據被更改,會立即執行beforeUpdate鉤子函數,鉤子函數執行後後Vue的虛擬Dom機制會重新構建虛擬Dom與上一次的虛擬Dom樹利用diff算法進行對比之後重新渲染。
    在這裏插入圖片描述

  2. 當更新完成後,會執行updated鉤子函數執行,此時數據已經更改完成,Dom也重新render完成。
    在這裏插入圖片描述

三、銷燬階段

  1. 當經調用$destroy方法後,立即執行beforeDestroy鉤子。

  2. 銷燬實例與DOM之間的關聯,解綁它的全部指令及事件監聽器(並不能清除已有的頁面上的DOM),之後會執行destroyed鉤子。
    在這裏插入圖片描述
    beforeDestroy和destroyed用法相似,一般在這裏做善後工作,如清除計時器、清除非指令綁定的事件等等

PS:銷燬實例與DOM之間的關聯,解綁它的全部指令及事件監聽器,並不能清除已有的頁面上的DOM。
在這裏插入圖片描述
在這裏插入圖片描述

vue中父級與子組件生命週期的先後順序

修改一下上面的例子,在實例中掛載一個子組件,通過這段代碼來看一下父級與子組件生命週期的先後順序

<div id="app">
  <input type="text" v-model="message">
  <button v-on:click="handleDestroy">銷燬父組件</button>
  <button v-on:click="flag=!flag">銷燬/重建子組件</button>
  <child-a :msg="message" inline-template v-if="flag">
    <div class="child-a">
      <label>{{msg}}</label><input type="text" v-model="title">
    </div>
  </child-a>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      message: '父組件信息',
      flag: true
    },
    methods: {
      handleDestroy() {
        this.$destroy();
      }
    },
    components: {
      'childA': {
        data() {
          return {
            title: '子組件',
          }
        },
        props: ['msg'],
        beforeCreate() {
          console.log("%c%s", "color:green", '(1)、子組件 beforeCreate');
        },
        created() {
          console.log("%c%s", "color:green", '(2)、子組件 created');
        },
        beforeMount() {
          console.log("%c%s", "color:green", '(3)、子組件 beforeMount');
        },
        mounted() {
          console.log("%c%s", "color:green", '(4)、子組件 mounted');
        },
        beforeUpdate() {
          console.log("%c%s", "color:green", '(5)、子組件 beforeUpdate');
        },
        updated() {
          console.log("%c%s", "color:green", '(6)、子組件 updated ');
        },
        beforeDestroy() {
          console.log("%c%s", "color:green", '(7)、子組件 beforeDestroy ');
        },
        destroyed() {
          console.log("%c%s", "color:green", '(8)、子組件 destroyed ');
        }
      }
    },
    beforeCreate() {
      console.log("%c%s", "color:red", '1、實例創建之前: beforeCreate');
    },
    created() {
      console.log("%c%s", "color:red", '2、實例創建完畢: created');
    },
    beforeMount() {
      console.log("%c%s", "color:red", '3、實例掛載之前: beforeMount');
    },
    mounted() {
      console.log("%c%s", "color:red", '4、實例掛載完畢: mounted');
    },
    beforeUpdate() {
      console.log("%c%s", "color:red", '5、實例更新之前: beforeUpdate');
    },
    updated() {
      console.log("%c%s", "color:red", '6、實例更新完畢:updated');
    },
    beforeDestroy() {
      console.log("%c%s", "color:red", '7、實例銷燬之前:beforeDestroy');
    },
    destroyed() {
      console.log("%c%s", "color:red", '8、實例銷燬完畢:destroyed');
    }
  });
</script>

1、當父組件執行完beforeMount,會依次執行子組件的生命週期鉤子,直到全部子組件掛載到實例上(執行完子組件的mounted鉤子),父組件纔會進入mounted鉤子。
在這裏插入圖片描述在這裏插入圖片描述
2、更新子組件的數據,不會觸發父組件的生命週期鉤子
3、如果子組件引用了父組件的數據,父組件數據更新時,執行順序是:
在這裏插入圖片描述
4、銷燬父組件時,同時銷燬其包含的子組件,同前面說的一樣,子組件的視圖也不會消失
在這裏插入圖片描述
5、本例中,通過v-if的方法銷燬子組件時,同時會觸發父組件的更新鉤子

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章