第十六節(jié):Vue生命周期與鉤子函數(shù)

前沿:
通過前面幾節(jié)的學(xué)習(xí),我們已經(jīng)對(duì)vue有了初步的了解,vue可以幫我們干什么,而接下來就介紹vue的生命周期和它常用的鉤子函數(shù),那么我們就來看看對(duì)于vue的生命周期.

1. 理解生命周期的含義

生命周期:就是一個(gè)組件從實(shí)例化創(chuàng)建并添加到DOM開始 ,一直到組件被銷毀的整個(gè)過程 。

生命周期函數(shù)(鉤子函數(shù)): 就是在Vue生命周期的整個(gè)過程的不同階段被調(diào)用的函數(shù)


2. 生命周期圖

首先來一下官網(wǎng)的對(duì)于vue生命周期的圖解, 官網(wǎng)上目前有8個(gè)生命周期函數(shù),
還有兩個(gè)我們之后再看. 先看看基本的8個(gè)鉤子函數(shù)

生命周期圖.png


3. 鉤子函數(shù)的理解

通過打斷點(diǎn)的方式,讓我們好好理解聲明周期的鉤子函數(shù), 你們也可以自己復(fù)制代碼進(jìn)行測(cè)試好好理解Vue的鉤子函數(shù)

<script>
    new Vue({
        el: "#app",
        data:{},
        methods:{},
        
        // 1. 在實(shí)例化之前被調(diào)用 
        beforCreate: function(){
            // 這個(gè)方法的時(shí)候data還沒有加載,所以此方法用不到
            // 一般不會(huì)再這里處理什么事情
            alert("組件實(shí)例化之前執(zhí)行的函數(shù)");
            debugger;
        },
        
        // 2. 實(shí)例化初始之后,被添加到DOM元素之前觸發(fā)
        created: function(){
            // 可以在這里發(fā)送ajax,初始化操作
            alert("組件實(shí)例化完畢,但頁(yè)面還未顯示");
            debugger;
        },
        
        // 3. 在元素(虛擬DOM)已經(jīng)準(zhǔn)備好被添加到DOM,但是還沒有添加時(shí)觸發(fā)
        beforeMount: function(){
            // 要保證有el,或者vm.$mount() 否則這里不會(huì)執(zhí)行
            alert("組件掛載前,但頁(yè)面還未顯示,但是虛擬DOM已經(jīng)配置");
            debugger;
        },
        
        // 4. 會(huì)在元素創(chuàng)建后觸發(fā)
        mounted: function(){
            //  如果有template屬性模板,會(huì)用模板替換外部的el,只要有此屬性,直接卸載外部el找中的內(nèi)
            // 這將沒有任何意義了
            //  template只能有一個(gè)更元素,不能是文本節(jié)點(diǎn), 
            // 真實(shí)的dom渲染完了,可以操作dom了
            alert("組件掛載后,此方法執(zhí)行后,頁(yè)面顯示");
            debugger;
        },
        
        // 5. 在數(shù)據(jù)更新將要對(duì)DOM做一些修改時(shí)觸發(fā)
        beforeUpdate: function(){
            //  當(dāng)頁(yè)面依賴的數(shù)據(jù)發(fā)生變化時(shí)才執(zhí)行,一般用watch來替換,這個(gè)方法不好用
            // 頁(yè)面依賴的數(shù)據(jù)發(fā)生變化,數(shù)據(jù)已變化,頁(yè)面還沒有渲染
            alert("組件更新前,但頁(yè)面還未顯示,但是虛擬DOM已經(jīng)配置");
            debugger;
        },
        
        // 6. 后在DOM的更新已經(jīng)完成后觸發(fā)
        updated: function(){
            // 重新渲染頁(yè)面后執(zhí)行, 可以操作DOM了
            alert("組件更新后,此方法執(zhí)行后,頁(yè)面顯示");
            debugger;
        },
            
         // 7. 在組件即將被銷毀并且從DOM上移出時(shí)觸發(fā)
        beforeDestroy: function(){
            //沒什么意義,死了就什么都干不了了
            alert("組件銷毀前");
            debugger;
        }
    
        // 8. 組件被銷毀后觸發(fā)
        destroyed: function(){
            alert("組件銷毀");
            debugger;
        }
    })
</script>

實(shí)踐是檢驗(yàn)道理的唯一標(biāo)準(zhǔn),
這里只能通過注釋來介紹一下vue的鉤子函數(shù)的意義。
想要詳細(xì)了解還需要你親自測(cè)試體會(huì)

生命周期鉤子的 this 上下文指向調(diào)用它的 Vue 實(shí)例。


通過這張生命周期圖,我們發(fā)現(xiàn)我們之前還有一些內(nèi)容沒有測(cè)試到, 諸如使用$mount綁定DOM元素, 實(shí)例化時(shí)自定義template模板等,那么接下來就好好測(cè)試一些,生命周期圖所講述的內(nèi)容


4. 綁定節(jié)點(diǎn)

我們之前學(xué)到一直是使用vue配置對(duì)象里的el來綁定DOM節(jié)點(diǎn)

生命周期圖告訴我們,如果我們沒有el屬性就會(huì)查找vue實(shí)例對(duì)象有沒有通過$mount方法來綁定DOM元素
其實(shí)就算你是用el綁定了DOM元素,在Vue源碼中也是會(huì)轉(zhuǎn)為$mount處理

<div id="app">

    <div v-html="msg"></div>
</div>
<div id="haha"></div>

<script>
    const vm = new Vue({
        el:"#app",
        data: {
           msg:"hello"
        },

    })
    vm.$mount("#haha")
</script>

同時(shí)我們還會(huì)發(fā)現(xiàn),如果el$mount都存在,綁定的元素有差異,那么以el為主,因?yàn)樯芷趫D告訴我們只有當(dāng)el屬性不存在的時(shí)候,才會(huì)查看$mount方法


5. template模板編譯

我們之前學(xué)習(xí)一直使用的都是沒有template模板的, 根據(jù)生命周期圖顯示,如果我們沒有template,模板,我們就會(huì)將el 屬性對(duì)應(yīng)的掛在點(diǎn)作為我們的模板

如果有template模板,我們就會(huì)用以后的模板替換之前的模板

<div id="app">
    {{ msg }}
</div>


<script>
    const vm = new Vue({
        el:"#app",
        template:"<div id='haha'>我是小當(dāng)家</div>",
        data: {
           msg:"hello"
        },
    })
</script>


5.1 注意template模板里只能有一個(gè)根標(biāo)簽

所以下面的寫法會(huì)報(bào)錯(cuò),是錯(cuò)誤的寫法

const vm = new Vue({
    template:`
        <div id='haha'>
            我是小當(dāng)家
        </div>
        <span></span>
    `,
    data: {
        msg:"hello"
    },
})


5.2 改變數(shù)據(jù)綁定的位置

如果有template 模板,我們動(dòng)態(tài)綁定的數(shù)據(jù),就需要在模板中綁定

<div id="app">
    {{ msg }}
</div>


<script>
    const vm = new Vue({
        el:"#app",
        template:"<div id='haha'>我是小當(dāng)家{{ msg }}</div>",
        data: {
           msg:"hello"
        },
    })
</script>


6. 關(guān)于mounted鉤子函數(shù)中獲取DOM元素的問題

6.1 正常在mounted鉤子函數(shù)里獲取DOM
<div id="app">
    <div v-html="msg"></div>
</div>

<script>
    const vm = new Vue({
        el:"#app",
        data: {
           msg:"<h2 id='box'>hello</h2>"
        },
        mounted(){
            console.log("mounted:");
            console.log(box);
        },
    })
</script>

我們會(huì)發(fā)現(xiàn)獲取DOM元素完全沒有問題,


6.2 更改DOM節(jié)點(diǎn)內(nèi)容

如果我們動(dòng)態(tài)的修改了DOM節(jié)點(diǎn),那么我們?cè)讷@取看看

<div id="app">

    <div v-html="msg"></div>
</div>
<script>

    const vm = new Vue({
        el:"#app",
        data: {
            msg:"<h2 id='box'>hello</h2>"
        },
        mounted(){
            // 動(dòng)態(tài)修改DOM 節(jié)點(diǎn)
            this.msg = `<h2 id="box">你好</h2>`
            // 獲取DOM 節(jié)點(diǎn)
            console.log(box);

        },
    })
</script>

這是我們就會(huì)發(fā)現(xiàn)我們獲取的還是原先的DOM節(jié)點(diǎn), 此時(shí)去獲取節(jié)點(diǎn)內(nèi)容就會(huì)有問題,
獲取的DOM節(jié)點(diǎn)并不是更改后最新的DOM節(jié)點(diǎn)


6.3 解決動(dòng)態(tài)DOM 節(jié)點(diǎn)的問題

我們可以使用$nextTice來解決此類問題

在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個(gè)方法,獲取更新后的 DOM。

$nextTick(),是將回調(diào)函數(shù)延遲在下一次dom更新數(shù)據(jù)后調(diào)用,簡(jiǎn)單的理解是:數(shù)據(jù)更新后,在dom重新渲染完畢,自動(dòng)執(zhí)行該函數(shù),

通過$nextTick 方法來異步操作vue實(shí)例

示例:

<div id="app">

    <div v-html="msg"></div>
</div>
<script>

    const vm = new Vue({
        el:"#app",
        data: {
            msg:"<h2 id='box'>hello</h2>"
        },
        mounted(){
            // 動(dòng)態(tài)修改DOM 節(jié)點(diǎn)
            this.msg = `<h2 id="box">你好</h2>`
            // 獲取DOM 節(jié)點(diǎn)
            console.log(box);
            
            // 通過$nextTick異步處理方法來獲取就會(huì)得到最新的值
            this.$nextTick(() => {
                console.log(box);
            })
        },
    })
</script>

上面的示例,我們打印了2次box ,box是DOM元素的id,可以用來獲取DOM元素, 但是此時(shí)兩次獲取的DOM元素展示的結(jié)果不一樣

$nextTick.png

第一次獲取box雖然數(shù)據(jù)已經(jīng)改變, 頁(yè)面也準(zhǔn)備重新渲染新的DOM元素, 但是此時(shí)DOM還沒有更新完成,就獲取box,獲取的就是原來的DOM元素內(nèi)容, $nextTick方法會(huì)在DOM元素更新完成以后才會(huì)觸發(fā)回調(diào)函數(shù),在回調(diào)函數(shù)中獲取的box才是更改后最新的DOM元素



建議在組件學(xué)習(xí)后在回來看:
帶有子組件的示例:

<div id="app">
    <child ref="child"></child>
</div>

<template id="child">
    <div>
        <span v-for="a in arr">{{a}}</span>
    </div>
</template>

<script>
    var vm = new Vue({   // 根實(shí)例
        el: '#app',
        data: {
            radio: 'home'
        },
        mounted() {
            console.log(1);     // 在執(zhí)行父組件的mounted
            // console.log(this.$refs.child.$el.innerHTML);
            // 這里打印的是 1,2,3的數(shù)組

            // 這里可以選擇$nextTick方法,這個(gè)是在頁(yè)面渲染完畢后執(zhí)行
            this.$nextTick(() => {
                console.log(this.$refs.child.$el.innerHTML);  // 這個(gè)時(shí)候才4,5,6
            })
        },
        components: {
            child: {
                template: '#child',
                data() {
                    return { arr: [1, 2, 3] }
                },
                mounted() {
                    console.log(2);    // 先打印子組件的mounted
                    this.arr = [4, 5, 6]; // 說明這里mounted是異步的
                }
            }
        }
    });
</script>

顯示結(jié)果

帶組件的示例.png

通過實(shí)例發(fā)現(xiàn),是不是用$nextTick方法在組件數(shù)據(jù)更新以后獲取的DOM元素的內(nèi)容都不一樣

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

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