Vue系列之—Vue生命周期詳解


一、介紹

       Vue實例有一個完整的生命周期,也就是從開始創建、初始化數據、編譯模板、掛載Dom、渲染→更新→渲染、銷毀等一系列過程,我們稱這是Vue的生命周期。通俗說就是Vue實例從創建到銷毀的過程,就是生命周期。

每一個組件或者實例都會經歷一個完整的生命周期,總共分為三個階段:初始化、運行中、銷毀。

  1. 實例、組件通過new Vue() 創建出來之后會初始化事件和生命周期,然后就會執行beforeCreate鈎子函數,這個時候,數據還沒有掛載,只是一個空殼,無法訪問到數據和真實的dom,一般不做操作

  2. 掛載數據,綁定事件等等,然后執行created函數,這個時候已經可以使用到數據,也可以更改數據,在這里更改數據不會觸發updated函數,在這里可以在渲染前倒數第二次更改數據的機會,不會觸發其他的鈎子函數,一般可以在這里做初始數據的獲取

  3. 接下來開始找實例或者組件對應的模板,編譯模板為虛擬dom放入到render函數中准備渲染,然后執行beforeMount鈎子函數,在這個函數中虛擬dom已經創建完成,馬上就要渲染,在這里也可以更改數據,不會觸發updated,在這里可以在渲染前最后一次更改數據的機會,不會觸發其他的鈎子函數,一般可以在這里做初始數據的獲取

  4. 接下來開始render,渲染出真實dom,然后執行mounted鈎子函數,此時,組件已經出現在頁面中,數據、真實dom都已經處理好了,事件都已經掛載好了,可以在這里操作真實dom等事情...

  5. 當組件或實例的數據更改之后,會立即執行beforeUpdate,然后vue的虛擬dom機制會重新構建虛擬dom與上一次的虛擬dom樹利用diff算法進行對比之后重新渲染,一般不做什么事兒

  6. 當更新完成后,執行updated,數據已經更改完成,dom也重新render完成,可以操作更新后的虛擬dom

  7. 當經過某種途徑調用$destroy方法后,立即執行beforeDestroy,一般在這里做一些善后工作,例如清除計時器、清除非指令綁定的事件等等

  8. 組件的數據綁定、監聽...去掉后只剩下dom空殼,這個時候,執行destroyed,在這里做善后工作也可以

二、生命周期圖示

img

三、生命周期鈎子函數

生命周期鈎子 詳細
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鈎子之外,其他鈎子均在服務器端渲染期間不被調用。)

四、實際操作

可視化觀察生命周期鈎子函數執行時狀態變化的情況

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/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);
        },
        beforeUpdate: function () {
            console.group('beforeUpdate 更新前狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
            console.log('beforeUpdate == ' + document.getElementsByTagName('p')[0].innerHTML);
        },
        updated: function () {
            console.group('updated 更新完成狀態===============》');
            var state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            console.log(this.$el);
            console.log(state);
            console.log('updated == ' + document.getElementsByTagName('p')[0].innerHTML);
        },
        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> 包裹,為接下來的測試作准備。在谷歌瀏覽器打開開發者工具,開始測試!

根據打印結果:

  1、beforeCreate執行時:data和el均未初始化,值為undefined

  2、created執行時:Vue 實例觀察的數據對象data已經配置好,已經可以得到app.message的值,但Vue 實例使用的根 DOM 元素el還未初始化

  3、beforeMount執行時:data和el均已經初始化,但從{{message}}等現象可以看出此時el並沒有渲染進數據el的值為“虛擬”的元素節點

  4、mounted執行時:此時el已經渲染完成並掛載到實例

beforecreated:el 和 data 並未初始化 ;created:完成了 data 數據的初始化,el沒有;beforeMount:完成了 el 和 data 初始化 ;mounted :完成掛載。(注意:在beforeMount階段應用的 Virtual DOM(虛擬Dom)技術,先把坑占住了,到后面mounted掛載的時候再把值渲染進去。)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM