今天女朋友问我vue的生命周期合并策略是什么,我敲了敲她的小脑袋说(假装自己有女朋友):
vue的生命周期是beforCreate,created,beforeMount等一大堆~如图:
在讲合并策略之前,我们首先要知道vue.mixin,就是混入,可以把一些页面公共的方法,数据抽离出来。在合并时如果mixin的数据对象和组件的数据发生冲突时以组件数据优先;同名钩子函数将会混合为一个数组,都将被调用到,但是混入对象的钩子将在组件自身钩子之前调用;值为对象的选项,例如 methods, components 和 directives,将被混合为同一个对象,两个对象键名冲突时,取组件对象的键值对。那么我们就来实现这个静态方法mixn吧。上代码!
//我们知道生命周期钩子函数的合并策略和数据有一些不同,生命周期钩子函数要处理成数组,//所以我们要分开梳理const LIFECYCLE_HOOKS = [ 'beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeUpdate', 'updated', 'beforeDestroy', 'destroyed']// 这个用来存放特殊策略的,比如strategys.computed等等let strategys = {};// 这就是生命周期钩子函数合并策略,我们传入2个参数,一个原有的,一个mixin的function mergeHook(parentVal,childVal){ // 如果有新传入的 if(childVal){ if(parentVal){ // 原有的也有,那么直接添加上 return parentVal.concat(childVal) }else{ // 原有的没有直接返回一个数组。初始化时也会用到这个 return [childVal] } }else{ // 如果没有传入mixin,那就直接返回原有的,因为我们在数据劫持时也要合并, // 所以原有肯定也是数组 return parentVal }}// for循环给每个生命周期钩子函数加上自己独有的策略LIFECYCLE_HOOKS.forEach(hook=>{ strategys[hook] = mergeHook;})// 这是合并入口方法export function mergeOptions(parent,child){ // 定义一个空json,用来存放数据,并返回 const options = {}; // 我们以新传入的为准,所以,我们循环原有的 for(let key in parent){ mergeField(key) } // 我们在循环mixin的,排除原有已经循环过的 for(let key in child){ if(!parent.hasOwnProperty(key)){ mergeField(key) } } function mergeField(key){ // 如果是特殊规则则执行特殊的(如生命周期钩子函数,computed等) if(strategys[key]){ return options[key] = strategys[key](parent[key],child[key]) } // 如果都是对象,则合并 if(typeof parent[key] ==='object' && typeof child[key]==='object'){ options[key] = { ...parent[key], ...child[key] } }else if(child[key] ==null){ // 没有mixin则是原来的 options[key] = parent[key]; }else{ // 其他则已mixin为准 options[key] = child[key] } } return options}
同时我们需要实现一个方法用来调用存起来生命周期钩子函数,循环依次调用即可
export function callHook(vm,hook){ const handlers = vm.$options[hook]; if(handlers){ for(let i =0;i handlers[i].call(vm) } }}
就酱,生命周期钩子函数就完成了
Vue.prototype._init = function(options){ const vm = this; // vm.$options = options; vm.$options = mergeOptions(vm.constructor.options,options) console.log(vm.$options,this.$options) callHook(vm,'beforeCreate') initState(vm);//分割代码 callHook(vm,'created') if(vm.$options.el){ vm.$mount(vm.$options.el) } }export function mountComponent(vm,el){ const options = vm.$options; vm.$el = el; callHook(vm,'beforeMount') let updateComponent = ()=>{ vm._update(vm._render()) } new Watcher(vm,updateComponent,()=>{},true);//true 表示他是一个渲染watcher callHook(vm,'mounted')}