Vue 2.0 源码分析(九) 生命周期详解
程序员文章站
2022-04-10 21:17:33
用法 先来看看官网的介绍: 主要有八个生命周期,分别是: beforeCreate、created、beforeMount、mounted、beforeupdate、updated 、beforeDestroy和destroyed,分别对应八个不同的时期,另外还有两个activated和deacti ......
用法
先来看看官网的介绍:
主要有八个生命周期,分别是:
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实例的message值做了更新操作,此时控制台输出如下:
当我们点击测试(销毁操作)按钮时,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生命周期函数 /*略*/ }; }