全局混入生命周期,在vue中组件中,会收集都放在 Vue.options上,在组件上的混入的生命周期会收集在组件实列this.$options上
先实现将mixin中的生命周期函数收集到Vue.options,
形成这样的形势
全局mixin是给全部Vue文件添加一些公用的实例,我们需要实现一个Vue.mixin方法
来讲所有的全局注册的mixin里面的生命周期依次收集,我们这里只讲生命周期收集,像data,watch这些需要的自己添加策略去实现
Vue.options = {}
Vue.mixin=function(option){
let vmOption=this.options
this.options=mergeOptions(vmOption,option)
console.log('this.options',this.options)
}
先定义options,然后将用户写的mixin跟当前options上的生命周期进行合并
function mergeOptions (parent, child) {
//定义新的optins parent代表被合并的,child需要进行合并的
let options = {}
//这里合并,情况分为,被合并上面有的parent,child上面可能有可能没有
for (let key in parent) {
mergeField(key)
console.log(options)
}
//还有种情况,上面已经遍历了parent上面的所有的属性,但是child上面有的,但是parent上面没有的情况还
// 没有遍历到,所有需要遍及child,然后排除parent上有的
for (let key in child) {
if (!parent?.hasOwnProperty(key)) {
mergeField(key)
}
}
function mergeField (key) {
// 合并字段
// 根据key 不同的策略来进行合并
if (strats[key]) {
options[key] = strats[key](parent[key], child[key])
} else {
// todo默认合并
options[key] = child[key]
}
}
return options
}
这里合并,情况分为,被合并上面有的parent,child上面可能有可能没有
//还有种情况,上面已经遍历了parent上面的所有的属性,但是child上面有的,但是parent上面没有的情况还
// 没有遍历到,所有需要遍及child,然后排除parent上有的
然后进行每一项的合并,在合并过程中我们需要用到策略模式
什么是策略模式呢?
策略模式的定义:定义一系列的算法,将他们一个个封装起来,使他们直接可以相互替换。
策略模式是开发中常用的第二种设计模式,它在开发中非常常见,由两部分组成。第一部分是策略类,封装了许多具体的,相似的算法。第二部分是环境类,接受客户请求,随后将请求委托给策略类。说的通俗一点就是将相同算法的函数存放在一个包装里边,每个函数用相同的方式拿出来,就叫做策略模式。
策略模式,可以帮助我们减少if else的写法
这里我们定义一个策略对象const strats = {}
我们需要合并到的生命周期方法合并的策略是一样的,但是在合并 data,watch computed,methods 是不一样的,所有我们需要写
strats.data=function (parent,child){}
strats.watch =function (parent,child){}
strats.computed=function (parent,child){}
每个的合并是不一样的,但是生命周期方法的合并是一样的,我们定义一个数组
const LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed'
]
然后遍历数组,为生命周期定义合并方法
LIFECYCLE_HOOKS.forEach(key=>{
strats[key]=mergeHook;
})
function mergeHook(parent,child){
if(child){
if(parent){
return parent.concat(child)
}else{
return [child]
}
}else{
return parent
}
}
在mergeHook中,进行真正的合并,如果child中没有,直接返回parent ,
测试
Vue.mixin({
created: function () {
var myOption = this.$options
if (myOption) {
console.log('1',myOption)
}
}
})
Vue.mixin({
created: function () {
var myOption = this.$options
if (myOption) {
console.log('2',myOption)
}
}
})
Vue.mixin({
created: function () {
var myOption = this.$options
if (myOption) {
console.log('3',myOption)
}
}
})
在这里 parent 第一次代表的是 Vue.options = {},child代表的是
第二次parent代表的是[created: function () {
var myOption = this.$options
if (myOption) {
console.log('1',myOption)
}
}
})],child代表的是
最终打印出来 console.log('this.options',this.options)
结果
在vue组件上的生命周期跟全局上的合并,是在vue初始化方法init里面Vue.prototype._init
Vue.prototype._init=function(option){
let vm =this
this.$options=option
this.$options=mergeOptions(vm.constructor.options,option)
console.log('this.$options',this.$options)
//初始化:watch,computed props data 生命周期
callHook(vm,'beforeCreate')
initState(vm)
callHook(vm,'created')
if(option.el){
vm.$mount(option.el)
}
}
这里我们为什么用vm.constructor.options指向的是vue.options,为什么不直接用vue.options,却要用他的实列,大家可以思考一下