首頁  >  文章  >  web前端  >  一文了解Vue2.0生命週期

一文了解Vue2.0生命週期

青灯夜游
青灯夜游轉載
2020-07-09 14:52:191970瀏覽

一文了解Vue2.0生命週期

網路上已經有很多關於vue生命週期的文章,我的這篇文章的由來,其實是我對官網上描述的一句話的思考與理解:「el被新創建的vm.$el替換”,所以文章更多的內容可能是在對vue生命週期中“created -> beforeMount -> mounted” 過程的理解。

beforeCreate --> created 之間

#在這個階段初始化事件,進行資料觀測。

created

vue實例建立完後被調用,此時已經完成了資料觀測(data observer),屬性和方法的運算,watch/event 事件回調的配置。

可呼叫methods中的方法,存取和修改data中的數據,並觸發響應式變化使DOM渲染更新,觸發watch中相應的方法,computed相關屬性進行重新計算。

一般在created時,進行ajax請求初始化實例資料。

此時,vm.$el不可見。

created --> beforeMount 之間

 在這個過程中,

  a、先判斷實例中是否有el選項,有的話繼續向下編譯,沒有的話會停止編譯,直到vm.$mount(el)被呼叫時才繼續(el是掛載的DOM節點);

  b、接下來判斷實例中是否有template,有的話將其作為模板編譯成rander函數;

  c、沒有template的話就,就將 掛載DOM元素的html(即el所對應的DOM元素及其內部的元素)提取出來作為模板編譯;

*註:el所對應的DOM元素不能為body/html元素,因為在後面vue實例掛載時,el所對應的DOM元素及其內部的元素會被模板渲染出來的新的DOM所取代。

  d、如果實例物件中有rander函數,就直接透過它進行渲染運算。

優先權:rander函數> template > 外部html

##此時,rander函數已經準備好並首次被呼叫。

在這個過程中,$el被初始化為實例中el選項所對應的DOM元素,所以在beforeMount時,用vm.$el取得到的是掛載DOM元素的html。

beforeMount

# beforeMount被呼叫時,此時$el可見。

beforeMount --> mounted 之間

在這個過程中,

el被新建立的vm.$el所取代,並完成實例的掛載。即實例中的el選項被模板渲染創建出來的DOM元素所替換,頁面中的掛載點被渲染出的vue實例代碼段所替換。

Mounted

此時實例已掛載到DOM上,可以透過DOM API取得實例中DOM節點。在控制台列印vm.$el,發現先前的掛載點及內容已被替換成新的DOM。

下面透過栗子看一下這兩個過程。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
</head>
<body>
<div id="app">
    <a id=&#39;ela&#39; href="">{{message}}</a>
</div>
</body>
<script>
    var app = new Vue({
        el: '#app',
        data: function () {
            return {
                message: 'hello'
            };
        },
        template: '<p id="elp">{{message}}</p>',
        beforeMount: function () {
            console.group('beforeMount 挂载前状态===============》');
            let state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            let a = document.getElementById('ela');
            let p = document.getElementById('elp');
            console.log(this.$el);
            console.log(state);
            console.log(a);    // <a id=&#39;ela&#39; href="">{{message}}</a>
            console.log(p);     // null
        },
        mounted: function () {
            console.group('mounted 挂载结束状态===============》');
            let state = {
                'el': this.$el,
                'data': this.$data,
                'message': this.message
            }
            let a = document.getElementById('ela');
            let p = document.getElementById('elp');
            console.log(this.$el);
            console.log(state);
            console.log(a);    // null
            console.log(p);     // <p id="elp">father</p>
        }
</script>
</html>

用template/rander選項可以在控制台清楚的看到:掛載完成後,el被新建立的vm.$el取代。

掛載前是以初始的el和虛擬DOM的形式存在的,此時以template中的內容為模板,模板內容不可見,打印p標籤為null;

掛載後,模板渲染的新DOM取代原來的el,原el所對應的DOM不存在,印出a標籤為null。

 beforeUpdate 和 updated

當data物件中資料更新時,會觸發 beforeUpdate鉤子,此時view層還沒有更新。 beforeUpdate有下面幾個要注意的地方:

  a、

更新的資料必須在範本中直接或間接的使用,才會觸發beforeUpdate;

#  b、在掛載之前,data中資料更新不會觸發 beforeUpdate! 即在created、beforeMount時改變資料不會觸發更新流程;

  c、如果在beforeUpdate中,再次修改了該資料的值,會再次觸發beforeUpdate鉤子,進行兩次更新流程。

updated時,view層已更新完畢。

(在上面的程式碼中增加兩個鉤子)

mounted: function () {
    this.message = 'first';
//     this.show = false;        // 由于模板中没有用到show,所以show的改变不会触发beforeUpdate
},
beforeUpdate: function () {
    console.group('beforeUpdate 更新前状态===============》');
    let elp = document.getElementById('elp').innerHTML;
    console.log('message:' + this.message);
    console.log('DOM:' + elp);
},
updated: function () {
    console.group('updated 更新完成状态===============》');
    let elp = document.getElementById('elp').innerHTML;
    console.log('message:' + this.message);
    console.log('DOM:' + elp);
}

#

这里需要注意一点:view层我们需要通过innerHTML获取对应元素节点中的内容,而不能直接获取元素节点。直接获取元素节点,在控制台打印出来的view层中的数据都是更新之后的状态,不能打印出实时的正确的值,这应该和Chrome控制台的输出有关。

针对第三条,我们看一下下面的代码演示:

mounted: function () {
    this.message = 'first';
},
beforeUpdate: function () {
    console.group('beforeUpdate 更新前状态===============》');
    let elp = document.getElementById('elp').innerHTML;
    console.log('message:' + this.message);
    console.log('DOM:' + elp);
    this.message = 'second';    // 此时在beforeUpdate中再次修改了message的值
},
updated: function () {
    console.group('updated 更新完成状态===============》');
    let elp = document.getElementById('elp').innerHTML;
    console.log('message:' + this.message);
    console.log('DOM:' + elp);
}

 

这里我们可以清楚的看到进行了两次更新流程,但是对打印的结果有些疑问:第一次将message的值改为first,并且以first来渲染更新DOM,那么第一次调用updated时,message和DOM中的值都应该是first,而此时打印出来的时second。我理解的是,在第一次执行updated时,DOM就已经完成了第二次渲染更新,具体的过程还需要通过之后对源码的学习去理解。这里各位有不同的理解或者更详细的解释,可以在评论区留言,共同学习。

在这里,我们可以在beforeUpdate中加定时器去修改message的值,就可以等待第一次数据改变,DOM更新渲染完成后,进行第二次数据改变。

beforeUpdate: function () {
    console.group('beforeUpdate 更新前状态===============》');
    let elp = document.getElementById('elp').innerHTML;
    console.log('message:' + this.message);
    console.log('DOM:' + elp);
    var that = this;
    setTimeout(function(){
      that.message = 'second';
    });
//    this.message = 'second';    // 此时在beforeUpdate中再次修改了message的值
},

这里可以清楚看到两次数据改变时,数据和view层的更新状态。

beforeDestroy 和 destroyed

beforeDestroy:实例在销毁之前调用,此时实例仍然可用。

beforeDestroy -> destroyed: Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

destroyed:vue实例销毁后调用。

结尾:关于vue生命周期就总结完毕,有错误的地方烦请指出,会及时修改!

以上是一文了解Vue2.0生命週期的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除