Vue 2.0 源碼分析(九) 生命週期詳解

 用法html


先來看看官網的介紹:vue

主要有八個生命週期,分別是:node

beforeCreate、created、beforeMount、mounted、beforeupdate、updated   、beforeDestroy和destroyed,分別對應八個不一樣的時期,另外還有兩個activated和deactivated生命週期是對應Keep-Alive組件的vue-router

關於這八個生命週期的具體用法官網介紹的很詳細了,飛機入口:點我點我 ,另外還有一張比較直觀圖形介紹,飛機入口:點我點我vuex

例如:npm

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    <title>Document</title>    
</head>
<body>
    <div id="app">
        <p>{{message}}</p>
        <button @click="test1()">測試(更新操做)</button>
        <button @click="test2()">測試(銷燬操做)</button>
    </div>
    <script>
        Vue.config.productionTip=false;
        Vue.config.devtools=false;
        new Vue({
            el:'#app',
            data:{message:"Hello World!"},
            beforeCreate:function(){    console.log('beforeCreate');    },
            created:function(){         console.log('created');         },
            beforeMount:function(){     console.log('beforeMount');     },  
            mounted:function(){         console.log('mounted');         },
            beforeUpdate:function(){    console.log('beforeUpdate');    },
            updated:function(){         console.log('updated');         },
            beforeDestroy:function(){   console.log('beforeDestroy');   },
            destroyed:function(){       console.log('destroyed');       },
            methods:{
                test1:function(){this.message="Hello Vue!";},
                test2:function(){this.$destroy();},
            }
        })
    </script>
</body>
</html>

頁面渲染以下:api

渲染完成後控制檯輸出:app

當點擊了測試(更新操做)這個按鈕後,修改了Vue實例的message值作了更新操做,此時控制檯輸出以下:ide

當咱們點擊測試(銷燬操做)按鈕時,Vue實例作了銷燬操做,控制檯輸出以下:函數

 對於Vue的插件(包括官方的生態)來講,絕大多數都用到了beforeCreate()這個生命週期函數,能夠在實例化前混入一些屬性,以vuex爲例,以下:

  function applyMixin (Vue) { var version = Number(Vue.version.split('.')[0]); if (version >= 2) { Vue.mixin({ beforeCreate: vuexInit }); //若是Vue的版本大於2,則將vuexInit混入到beforeCreate生命週期函數,這樣vuex就會進行初始化 } else { // override init and inject vuex init procedure // for 1.x backwards compatibility. var _init = Vue.prototype._init; Vue.prototype._init = function (options) { if ( options === void 0 ) options = {}; options.init = options.init ? [vuexInit].concat(options.init) : vuexInit; _init.call(this, options); }; }

vue-router也是的,以下:

  Vue.mixin({                                     //混入了兩個生命週期,分別是beforeCreate和destroyed beforeCreate: function beforeCreate () { if (isDef(this.$options.router)) { this._routerRoot = this; this._router = this.$options.router; this._router.init(this); Vue.util.defineReactive(this, '_route', this._router.history.current); } else { this._routerRoot = (this.$parent && this.$parent._routerRoot) || this; } registerInstance(this, this); }, destroyed: function destroyed () { registerInstance(this); } });

 

源碼分析


 生命週期的源碼實現比較簡單,都是經過Vue內部的一個叫callHook()的全局函數執行的,以下:

function callHook (vm, hook) {    //第2914行 vm:vue實例 hook:對應的操做名(例如:beforeCreate、created等)
  // #7573 disable dep collection when invoking lifecycle hooks
  pushTarget();
  var handlers = vm.$options[hook];           //獲取生命週期函數    
  if (handlers) {
    for (var i = 0, j = handlers.length; i < j; i++) {    //遍歷生命週期函數
      try {
        handlers[i].call(vm);                               //執行該函數,以vm做爲上下文
      } catch (e) {
        handleError(e, vm, (hook + " hook"));
      }
    }
  }
  if (vm._hasHookEvent) {
    vm.$emit('hook:' + hook);
  }
  popTarget();
}

beforeCreate和created是在init()的時候執行的,以下:

Vue.prototype._init = function (options) {  //第4576行
    /**/
    vm._self = vm;
    initLifecycle(vm);
    initEvents(vm);
    initRender(vm);
    callHook(vm, 'beforeCreate');             //執行beforeCreate生命週期函數
    initInjections(vm); // resolve injections before data/props
    initState(vm);
    initProvide(vm); // resolve provide after data/props
    callHook(vm, 'created');                  //執行created生命週期函數

    /**/
  };

beforeMount和mounted是在掛載的時候在mountComponent()裏執行的,以下:

function mountComponent(vm, el, hydrating) {    //第2739行 掛載組件 vm:Vue實例  el:真實的DOM節點對象 
    /**/
    callHook(vm, 'beforeMount');                    //掛載前 執行生命週期裏的beforeMount事件
    var updateComponent;
    if ("development" !== 'production' && config.performance && mark) {         //開啓了性能追蹤時的分支
        /**/
    } else {
        updateComponent = function () {vm._update(vm._render(), hydrating);};   
    }

    new Watcher(vm, updateComponent, noop, null, true);                       
    hydrating = false;

    if (vm.$vnode == null) {                       
        vm._isMounted = true;                       //設置vm._isMounted爲true,表示已掛載
        callHook(vm, 'mounted');                    //執行生命週期裏的Mount事件
    }
    return vm
}

beforeUpdate是在Vue原型上的_update更新時觸發的,以下:

Vue.prototype._update = function (vnode, hydrating) { //第2646行 var vm = this;
    if (vm._isMounted) {                        //若是已經掛載了,則表示已經掛載了
        callHook(vm, 'beforeUpdate');               //則觸發beforeUpdate
    }
    /**/
}

updated是在nextTick()執行時當watcher執行完了以後觸發的,以下:

function callUpdatedHooks (queue) { //第3016行
  var i = queue.length;
  while (i--) {
    var watcher = queue[i];
    var vm = watcher.vm;
    if (vm._watcher === watcher && vm._isMounted) { //若是當前是渲染watcher,且已經掛載了
      callHook(vm, 'updated');                        //則觸發update生命週期函數
    }
  }
}

beforeDestroy和destroyed是在Vue原型的$destroy()方法裏觸發的,以下:

 Vue.prototype.$destroy = function () { //第2695行
    var vm = this;
    if (vm._isBeingDestroyed) {
      return
    }
    callHook(vm, 'beforeDestroy');        //觸發beforeDestroy生命週期函數
    /*這裏進行銷燬過程*/
    callHook(vm, 'destroyed');            //觸發destroyed生命週期函數
    /**/
  };
}
相關文章
相關標籤/搜索