深入全面了解VUE生命周期

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

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

生命周期:Vue 實例從開始創(chuàng)建、初始化數(shù)據(jù)、編譯模板、掛載Dom→渲染、更新→渲染、卸載等一系列過程,我們稱這是 Vue 的生命周期,各個階段有相對應的事件鉤子

1. 生命周期鉤子函數(shù)

下面這張圖是vue生命周期各個階段的執(zhí)行情況:

生命周期鉤子 組件狀態(tài) 最佳實踐
beforeCreate 實例初始化之后,this指向創(chuàng)建的實例,不能訪問到data、computed、watch、methods上的方法和數(shù)據(jù) 常用于初始化非響應式變量
created 實例創(chuàng)建完成,可訪問data、computed、watch、methods上的方法和數(shù)據(jù),未掛載到DOM,不能訪問到$el屬性,$ref屬性內(nèi)容為空數(shù)組 常用于簡單的ajax請求,頁面的初始化
beforeMount 在掛載開始之前被調(diào)用,beforeMount之前,會找到對應的template,并編譯成render函數(shù)
mounted 實例掛載到DOM上,此時可以通過DOM API獲取到DOM節(jié)點,$ref屬性可以訪問 常用于獲取VNode信息和操作,ajax請求
beforeupdate 響應式數(shù)據(jù)更新時調(diào)用,發(fā)生在虛擬DOM打補丁之前 適合在更新之前訪問現(xiàn)有的DOM,比如手動移除已添加的事件監(jiān)聽器
updated 虛擬 DOM 重新渲染和打補丁之后調(diào)用,組件DOM已經(jīng)更新,可執(zhí)行依賴于DOM的操作 避免在這個鉤子函數(shù)中操作數(shù)據(jù),可能陷入死循環(huán)
beforeDestroy 實例銷毀之前調(diào)用。這一步,實例仍然完全可用,this仍能獲取到實例 常用于銷毀定時器、解綁全局事件、銷毀插件對象等操作
destroyed 實例銷毀后調(diào)用,調(diào)用后,Vue 實例指示的所有東西都會解綁定,所有的事件監(jiān)聽器會被移除,所有的子實例也會被銷毀

注意:

  1. created階段的ajax請求與mounted請求的區(qū)別:前者頁面視圖未出現(xiàn),如果請求信息過多,頁面會長時間處于白屏狀態(tài)
  2. mounted 不會承諾所有的子組件也都一起被掛載。如果你希望等到整個視圖都渲染

完畢,可以用 vm.$nextTick

  1. vue2.0之后主動調(diào)用$destroy()不會移除dom節(jié)點,作者不推薦直接destroy這種做法,如果實在需要這樣用可以在這個生命周期鉤子中手動移除dom節(jié)點

2. 單個組件的生命周期

現(xiàn)根據(jù)實際代碼執(zhí)行情況分析:

<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()
        }
    }
}

初始化組件時,打印:

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

當組件銷毀時,打印:

從打印結(jié)果可以看出:

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

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
    }
}

初始化組件時,打?。?a target="_blank" rel="nofollow">

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

當父組件data中的值變化時,打?。?a target="_blank" rel="nofollow">

當props改變時,打?。?a target="_blank" rel="nofollow">

當子組件銷毀時,打?。?a target="_blank" rel="nofollow">

當父組件銷毀時,打?。?/p>

從打印結(jié)果可以看出:

  1. 僅當子組件完成掛載后,父組件才會掛載
  2. 當子組件完成掛載后,父組件會主動執(zhí)行一次beforeUpdate/updated鉤子函數(shù)(僅首次)
  3. 父子組件在data變化中是分別監(jiān)控的,但是在更新props中的數(shù)據(jù)是關(guān)聯(lián)的(可實踐)
  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>

初始化組件時,打?。?a target="_blank" rel="nofollow">

當child1更新和銷毀時,打?。?a target="_blank" rel="nofollow">

當child2更新和銷毀時,打印:

當父組件銷毀時,打印

從打印結(jié)果可以看出:

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

5. 宏mixin的生命周期

在上面的基礎上,添加一個mixin.js文件,內(nèi)容如下:

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],
    // ...
}

組件初始化時,打?。?a target="_blank" rel="nofollow">

組件銷毀時,打?。?a target="_blank" rel="nofollow">

從打印結(jié)果可以看出: mixin中的生命周期與引入該組件的生命周期是僅僅關(guān)聯(lián)的,且mixin的生命周期優(yōu)先執(zhí)行

內(nèi)容摘自: vue 生命周期深入

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容