Vue生命週期深刻

下一篇:Vue組件通訊深刻javascript

這篇博客將會從下面四個常見的應用詮釋組件的生命週期,以及各個生命週期應該幹什麼事html

  1. 單組件的生命週期
  2. 父子組件的生命週期
  3. 兄弟組件的生命週期
  4. 宏mixin的生命週期

建議:博客中的例子都放在vue_blog_project工程中,推薦結合工程實例與博客一同窗習vue

生命週期:Vue 實例從開始建立、初始化數據、編譯模板、掛載Dom→渲染、更新→渲染、卸載等一系列過程,咱們稱這是 Vue 的生命週期,各個階段有相對應的事件鉤子

1. 生命週期鉤子函數

下面這張圖是vue生命週期各個階段的執行狀況:java

clipboard.png

生命週期鉤子 組件狀態 最佳實踐
beforeCreate 實例初始化以後,this指向建立的實例,不能訪問到data、computed、watch、methods上的方法和數據 經常使用於初始化非響應式變量
created 實例建立完成,可訪問data、computed、watch、methods上的方法和數據,未掛載到DOM,不能訪問到$el屬性,$ref屬性內容爲空數組 經常使用於簡單的ajax請求,頁面的初始化
beforeMount 在掛載開始以前被調用,beforeMount以前,會找到對應的template,並編譯成render函數 -
mounted 實例掛載到DOM上,此時能夠經過DOM API獲取到DOM節點,$ref屬性能夠訪問 經常使用於獲取VNode信息和操做,ajax請求
beforeupdate 響應式數據更新時調用,發生在虛擬DOM打補丁以前 適合在更新以前訪問現有的DOM,好比手動移除已添加的事件監聽器
updated 虛擬 DOM 從新渲染和打補丁以後調用,組件DOM已經更新,可執行依賴於DOM的操做 避免在這個鉤子函數中操做數據,可能陷入死循環
beforeDestroy 實例銷燬以前調用。這一步,實例仍然徹底可用,this仍能獲取到實例 經常使用於銷燬定時器、解綁全局事件、銷燬插件對象等操做
destroyed 實例銷燬後調用,調用後,Vue 實例指示的全部東西都會解綁定,全部的事件監聽器會被移除,全部的子實例也會被銷燬 -

注意:git

  1. created階段的ajax請求與mounted請求的區別:前者頁面視圖未出現,若是請求信息過多,頁面會長時間處於白屏狀態
  2. mounted 不會承諾全部的子組件也都一塊兒被掛載。若是你但願等到整個視圖都渲染完畢,能夠用 vm.$nextTick
  3. vue2.0以後主動調用$destroy()不會移除dom節點,做者不推薦直接destroy這種作法,若是實在須要這樣用能夠在這個生命週期鉤子中手動移除dom節點

2. 單個組件的生命週期

現根據實際代碼執行狀況分析:github

<template>
    <div>
        <h3>單組件</h3>
        <el-button @click="dataVar += 1">更新 {{dataVar}}</el-button>
        <el-button @click="handleDestroy">銷燬</el-button>
    </div>
</template>
export default {
    data() {
        return {
            dataVar: 1
        }
    },
    beforeCreate() {
        this.compName = 'single'
        console.log(`--${this.compName}--beforeCreate`)
    },
    created() {
        console.log(`--${this.compName}--created`)
    },
    beforeMount() {
        console.log(`--${this.compName}--beforeMount`)
    },
    mounted() {
        console.log(`--${this.compName}--mounted`)
    },
    beforeUpdate() {
        console.log(`--${this.compName}--beforeUpdate`)
    },
    updated() {
        console.log(`--${this.compName}--updated`)
    },
    beforeDestroy() {
        console.log(`--${this.compName}--beforeDestroy`)
    },
    destroyed() {
        console.log(`--${this.compName}--destroyed`)
    },
    methods: {
        handleDestroy() {
            this.$destroy()
        }
    }
}

初始化組件時,打印:
clipboard.pngajax

當data中的值變化時,打印:
clipboard.pngsegmentfault

當組件銷燬時,打印:
clipboard.pngapi

從打印結果能夠看出:數組

  1. 初始化組件時,僅執行了beforeCreate/Created/beforeMount/mounted四個鉤子函數
  2. 當改變data中定義的變量(響應式變量)時,會執行beforeUpdate/updated鉤子函數
  3. 當切換組件(當前組件未緩存)時,會執行beforeDestory/destroyed鉤子函數
  4. 初始化和銷燬時的生命鉤子函數均只會執行一次,beforeUpdate/updated可屢次執行

3. 父子組件的生命週期

將單組件做爲基礎組件(因爲props在beforeCreate()中未初始化),須要作以下更改:

props: {
    compName: {
        type: String,
        default: 'single'
    }
},
beforeCreate() {
    // this.compName = 'single'
    // console.log(`--${this.compName}--beforeCreate`)

    console.log(` --data未初始化--beforeCreate`)
},

父組件代碼以下:

<template>
    <div class="complex">
        <h3>複雜組件</h3>
        <lifecycle-single compName="child"></lifecycle-single>
    </div>
</template>
const COMPONENT_NAME = 'complex'

import LifecycleSingle from './LifeCycleSingle'

export default {
    beforeCreate() {
        console.log(`--${COMPONENT_NAME}--beforeCreate`)
    },
    created() {
        console.log(`--${COMPONENT_NAME}--created`)
    },
    beforeMount() {
        console.log(`--${COMPONENT_NAME}--beforeMount`)
    },
    mounted() {
        console.log(`--${COMPONENT_NAME}--mounted`)
    },
    beforeUpdate() {
        console.log(`--${COMPONENT_NAME}--beforeUpdate`)
    },
    updated() {
        console.log(`--${COMPONENT_NAME}--updated`)
    },
    beforeDestroy() {
        console.log(`--${COMPONENT_NAME}--beforeDestroy`)
    },
    destroyed() {
        console.log(`--${COMPONENT_NAME}--destroyed`)
    },
    components: {
        LifecycleSingle
    }
}

初始化組件時,打印:
clipboard.png

當子組件data中的值變化時,打印:
clipboard.png

當父組件data中的值變化時,打印:
clipboard.png

當props改變時,打印:
clipboard.png

當子組件銷燬時,打印:
clipboard.png

當父組件銷燬時,打印:
clipboard.png

從打印結果能夠看出:

  1. 僅當子組件完成掛載後,父組件纔會掛載
  2. 當子組件完成掛載後,父組件會主動執行一次beforeUpdate/updated鉤子函數(僅首次)
  3. 父子組件在data變化中是分別監控的,可是在更新props中的數據是關聯的(可實踐)
  4. 銷燬父組件時,先將子組件銷燬後纔會銷燬父組件

4. 兄弟組件的生命週期

在上面的基礎上,複雜組件作以下更改

<template>
    <div class="complex">
        <h3>複雜組件</h3>
        <lifecycle-single compName="cihld1"></lifecycle-single>
        <lifecycle-single compName="child2"></lifecycle-single>
        <el-button @click="dataVar += 1">complex更新 {{dataVar}}</el-button>
        <el-button @click="handleDestroy">complex銷燬</el-button>
    </div>
</template>

初始化組件時,打印:
clipboard.png

當child1更新和銷燬時,打印:
clipboard.png

當child2更新和銷燬時,打印:
clipboard.png

當父組件銷燬時,打印:
clipboard.png

從打印結果能夠看出:

  1. 組件的初始化(mounted以前)分開進行,掛載是從上到下依次進行
  2. 當沒有數據關聯時,兄弟組件之間的更新和銷燬是互不關聯的

5. 宏mixin的生命週期

在上面的基礎上,添加一個mixin.js文件,內容以下:

const COMPONENT_NAME = 'lifecycleMixin'
export default {
    name: COMPONENT_NAME,
    beforeCreate() {
        console.log(`--${COMPONENT_NAME}--beforeCreate`)
    },
    created() {
        console.log(`--${COMPONENT_NAME}--created`)
    },
    beforeMount() {
        console.log(`--${COMPONENT_NAME}--beforeMount`)
    },
    mounted() {
        console.log(`--${COMPONENT_NAME}--mounted`)
    },
    beforeUpdate() {
        console.log(`--${COMPONENT_NAME}--beforeUpdate`)
    },
    updated() {
        console.log(`--${COMPONENT_NAME}--updated`)
    },
    beforeDestroy() {
        console.log(`--${COMPONENT_NAME}--beforeDestroy`)
    },
    destroyed() {
        console.log(`--${COMPONENT_NAME}--destroyed`)
    }
}

一樣的,複雜組件作以下更改:

import lifecycleMixin from './mixin'

export default {
    mixins: [lifecycleMixin],
    // ...
}

組件初始化時,打印:
clipboard.png

組件銷燬時,打印:
clipboard.png

從打印結果能夠看出:
mixin中的生命週期與引入該組件的生命週期是僅僅關聯的,且mixin的生命週期優先執行

下一篇:Vue組件通訊深刻

參考:

  1. vue官網教程
  2. vue官網API
  3. Vue2.0生命週期(組件鉤子函數與路由守衛)
相關文章
相關標籤/搜索