通俗易懂了解Vue組件的生命周期


1.前言

        在使用vue2.0進行日常開發中,我們總有這樣的需求,我就想在頁面剛一加載出這個表格組件時就發送請求去后台拉取數據,亦或者我想在組件加載前顯示個loading圖,當組件加載出來就讓這個loading圖消失等等這樣或那樣的需求,要實現這些需求,最重要的一點就是我怎么知道這個組件什么時候加載,換句話說我該什么時候向后台發送請求,為了解決這種問題,組件的生命周期鈎子函數就應運而生,博主自己作為一個vue2.0的初學者,以自己對vue2.0的組件生命周期的理解,力求以最通俗易懂的語言剖析vue2.0組件生命周期的各個過程,如有理解上的差錯,還請大佬們不吝賜教,話不多說,現在開始。

2.生命周期圖示

首先給出官方文檔上的組件生命周期過程圖示:

這是官方文檔給出的一個組件從被創建出來到最后被銷毀所要經歷的一系列過程,所以這個過程也叫做一個組件的生命周期圖。從圖中我們可以看到,一個組件從被創建到最后被銷毀,總共要經歷以下8個過程:

  1. beforeCreate:組件創建之前
  2. created:組件創建完畢
  3. beforeMount:組件掛載之前
  4. mounted:組件掛載完畢
  5. beforeUpate:組件更新之前
  6. upated:組件更新完畢
  7. beforeDestoy:組件銷毀之前
  8. destoyed:組件銷毀完畢

3.代碼演示

了解了組件生命周期各個過程后,我們放一波代碼,真正的看一看一個組件從生到死到底經歷了什么。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h1>{{ message }}</h1>
</div>


<script src="vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: '#app',
        data: {
            message : "難涼熱血——通俗易懂了解Vue2.0生命周期"
        },
        //組件創建之前
        beforeCreate(){
            console.group('beforeCreate 組件創建之前狀態===============》');
            console.log("%c%s", "color:red" , "el     : " + this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message)
        },
        //組件創建完畢
        created(){
            console.group('created 組件創建完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件掛載之前
        beforeMount(){
            console.group('beforeMount 組件掛載之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + (this.$el));
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件掛載完畢
        mounted(){
            console.group('mounted 組件掛載完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件更新之前
        beforeUpdate(){
            console.group('beforeUpdate 組件更新之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件更新完畢
        updated(){
            console.group('updated 組件更新完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件銷毀之前
        beforeDestroy(){
            console.group('beforeDestroy 組件銷毀之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件銷毀完畢
        destroyed(){
            console.group('destroyed 組件銷毀完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message)
        }
    })
</script>
</body>
</html>

運行上面代碼,我們在控制台中可以看到:

4.各個過程詳解

4.1 beforeCreate和created

針對組件創建之前和組件創建完畢這兩個過程,我們從控制台打印的結果中可以看出:

在組件創建之前beforeCreate:組件的el和data都未被創建。

在組件創建完畢后created:組件的數據data已經被創建好,但是el還處於未被創建狀態。

4.2 beforeMount和mounted

針對組件掛載之前和組件掛載完畢這兩個過程,我們從控制台打印的結果中可以看出:

在組件掛載之前beforeMount:組件的el就會被創建,但是值得注意的是:雖然數據data里的message早已經被創建好,但是它還未被應用到真是的DOM元素中

在組件掛載完畢mounted:組件的el,data都已經全部被創建好,並且data里的message也已經被正確的應用到DOM元素中。

 4.3 beforeUpdate和updated

針對組件更新之前和組件更新完畢這兩個過程,我們向控制台中輸入以下一行代碼:

app.message="十年飲冰,難涼熱血"

接着,頁面和控制台會變成如下樣子:

 

從圖中我們可以看到,當我們將data里的message值改變之后,會觸發組件的beforeUpdate和update鈎子函數。

 4.4 beforeDestroy和destroyed

針對組件銷毀之前和組件銷毀完畢這兩個過程,我們向控制台中輸入以下一行代碼:

app.$destroy();

輸入之后並回車,控制台發生了如下變化:

到此之后,整個組件便走完了自己的一生,從創建到被銷毀,銷毀之后,此時該組件將不再受vue管理,組件上的所有事件監聽都會被移除,所以指令都會被解綁。

如若不信,我們再執行以下一行代碼,試試再改變一下message的值,看看頁面還會不會有什么變化:

app.message="組件真的被銷毀了嗎?"

執行結果如圖:

從圖中我們可以看到,當組件被銷毀之后,再怎么對組件進行操作已經全然無用了。

5.總結

以上就是vue2.0中組件生命周期鈎子函數執行的各個過程以及執行的時機,但是這些鈎子函數到底該怎么用呢?針對前言中提出的需求我們又該怎么解決呢?在這里,給大家舉個例子:

例如有一個表格組件:

1.我們想在表格加載之前顯示個loading圖,那么我們可以在組件創建之前的鈎子函數beforeCreate里面將loading圖顯示。

2.當組件加載出來,我們可以在created鈎子函數里讓這個loading圖消失。

3.當表格被加載好之后我們想讓它馬上去拉取后台數據,那么我們可以在組件掛載之前的鈎子函數beforeMount里面去發送請求。

。。。

6.遺留問題

針對官方文檔中的組件生命周期流程圖中的這一部分(下圖所示),在上文中我們沒有說明,有的同學還有一些疑問,我們在這里統一說明一下:

 

在組件創建之后created和組件被掛載之前beforeMount這期間,發生的事情還是蠻多的,我們一步一步分析一下:

6.1 是否有el選項

當組件被創建之后,vue首先會去查看vue實例(一個組件就是一個vue實例)內是否有el選項。如果有,則正常往下進行,那如果沒有呢?我們來做做實驗,看如下代碼:

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h1>{{ message }}</h1>
</div>

<script src="vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        // el: '#app',
        data: {
            message : "難涼熱血——通俗易懂了解Vue2.0生命周期"
        },
        //組件創建之前
        beforeCreate(){
            console.group('beforeCreate 組件創建之前狀態===============》');
            console.log("%c%s", "color:red" , "el     : " + this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message)
        },
        //組件創建完畢
        created(){
            console.group('created 組件創建完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件掛載之前
        beforeMount(){
            console.group('beforeMount 組件掛載之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + (this.$el));
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件掛載完畢
        mounted(){
            console.group('mounted 組件掛載完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件更新之前
        beforeUpdate(){
            console.group('beforeUpdate 組件更新之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件更新完畢
        updated(){
            console.group('updated 組件更新完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件銷毀之前
        beforeDestroy(){
            console.group('beforeDestroy 組件銷毀之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件銷毀完畢
        destroyed(){
            console.group('destroyed 組件銷毀完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message)
        }
    })
</script>
</body>
</html>

 

與之前代碼不同的是,在上述代碼中我們注釋掉了這行代碼:

// el: '#app',

我們再來運行一下,看看控制台結果:

從結果中,我們可以看到,當vue實例中沒有el選項時,將不會再往下執行,意味着組件的生命周期就此中斷,

但如何再次讓組件起死回生呢,我們在控制台執行如下一行代碼:

app.$mount(“#app”)

再看結果:

執行完后,我們可以看到,組件又繼續往下生存了。

其實,vue實例內的el選項和app.$mount(“#app”)都是在告訴vue實例組件該掛載到哪個DOM節點上。

因此,當vue在發現vue實例內沒有el選項時,就會中斷組件的生命周期,直到明確了組件該掛載到哪個DOM節點上后再繼續往下執行。

6.2 是否有template選項

繼續往下看,在解決了vue實例內是否有el選項之后,vue還會查看實例內是否有template選項。在之前的代碼中,我們在vue實例內沒有加template選項,而是把template寫在實例外面,接下來,我們在實例內外都加上template,看看有什么區別,看如下代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <h1>這是vue實例外的template:{{ message }}</h1>
</div>

<script src="vue.js"></script>
<script type="text/javascript">
    var app = new Vue({
        el: '#app',
        data: {
            message : "難涼熱血——通俗易懂了解Vue2.0生命周期"
        },
        template:"<h1>這是vue實例內的template: {{ message }}</h1>", //組件創建之前
        beforeCreate(){
            console.group('beforeCreate 組件創建之前狀態===============》');
            console.log("%c%s", "color:red" , "el     : " + this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message)
        },
        //組件創建完畢
        created(){
            console.group('created 組件創建完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件掛載之前
        beforeMount(){
            console.group('beforeMount 組件掛載之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + (this.$el));
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件掛載完畢
        mounted(){
            console.group('mounted 組件掛載完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件更新之前
        beforeUpdate(){
            console.group('beforeUpdate 組件更新之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件更新完畢
        updated(){
            console.group('updated 組件更新完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件銷毀之前
        beforeDestroy(){
            console.group('beforeDestroy 組件銷毀之前狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message);
        },
        // 組件銷毀完畢
        destroyed(){
            console.group('destroyed 組件銷毀完畢狀態===============》');
            console.log("%c%s", "color:red","el     : " + this.$el);
            console.log(this.$el);
            console.log("%c%s", "color:red","data   : " + this.$data);
            console.log("%c%s", "color:red","message: " + this.message)
        }
    })
</script>
</body>
</html>

運行結果:

從結果中,我們可以看到:

當vue實例內有template選項時,vue會優先使用實力內的template,而外部的template將不會被使用;當vue實例內沒有template選項時,才會使用外部的template。

 

 至此,vue2.0組件生命周期說明完畢。

(完)


免責聲明!

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



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