欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue 2.0 源码分析(九) 生命周期详解

程序员文章站 2022-07-11 17:31:28
用法 先来看看官网的介绍: 主要有八个生命周期,分别是: beforeCreate、created、beforeMount、mounted、beforeupdate、updated 、beforeDestroy和destroyed,分别对应八个不同的时期,另外还有两个activated和deacti ......

 用法


先来看看官网的介绍:

Vue 2.0 源码分析(九) 生命周期详解

主要有八个生命周期,分别是:

beforecreate、created、beforemount、mounted、beforeupdate、updated   、beforedestroy和destroyed,分别对应八个不同的时期,另外还有两个activated和deactivated生命周期是对应keep-alive组件的

关于这八个生命周期的具体用法官网介绍的很详细了,飞机入口:点我点我 ,另外还有一张比较直观图形介绍,飞机入口:点我点我

例如:

<!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>

页面渲染如下:

Vue 2.0 源码分析(九) 生命周期详解

渲染完成后控制台输出:

Vue 2.0 源码分析(九) 生命周期详解

当点击了测试(更新操作)这个按钮后,修改了vue实例的message值做了更新操作,此时控制台输出如下:

Vue 2.0 源码分析(九) 生命周期详解

当我们点击测试(销毁操作)按钮时,vue实例做了销毁操作,控制台输出如下:

Vue 2.0 源码分析(九) 生命周期详解

 对于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生命周期函数
    /*略*/
  };
}