Vue mixin 原理分析二

1.mixin什么时候开始合并

合并分为两种

1.1 全局mixin基础全局options合并

Vue.mixin = function(mixin) {
    this.options = mergeOptions(this.options, mixin);
    return this;
}

其中基础全局options就是指components, directives, filters, 这3者一开始就挂载到了Vue.options上,所以这三个是最先存在的全局options

1.2 全局options和自定义options合并

在调用Vue时,首先进行的就是合并

function Vue(options) {
    vm.$options = mergeOptions(
        全局component,
        全局directive,
        全局filter,
        options,
        vm
    );
}

2. mixin怎么合并

合并mixin核心方法就是mergeOptions,我们来看看这个函数做了什么

function mergeOptions(parent, child, vm) {    
    // 使用递归的方式
    // 遍历mixins,parent 先和 mixins 合并,然后在和 child 合并
    if (child.mixins) {        
        for (var i = 0, l = child.mixins.length; i < l; i++) {
            parent = mergeOptions(parent, child.mixins[i], vm);
        }
    }    
    var options = {}, key;    
    // 先处理 parent 的 key,保存在options
    for (key in parent) {
        mergeField(key);
    }   
    // 遍历 child 的key ,合并补上parent中没有的key,也保存在options
    for (key in child) {        
        if (!parent.hasOwnProperty(key)) {
            mergeField(key);
        }
    }    
    // 拿到相应类型的合并函数,进行合并字段,strats 请看下面
    function mergeField(key) {    
        // strats 保存着各种字段的处理函数,否则使用默认处理
        var strat = strats[key] || defaultStrat;    
        // 相应的字段处理完成之后,会完成合并的选项
        options[key] = strat(parent[key], child[key], vm, key);
    }    
    return options
}

defaultStrat这是默认的处理函数,可以简单理解为如果有优先级较高option,就优先使用优先级较高的。

// 组件options > 组件mixin options > 全局options
var defaultStrat = function (parentVal, childVal) {
    return childVal === undefined ?
        parentVal :
        childVal;
}

data的处理稍微有点复杂,主要的流程有两步1. 两个data组装成一个函数,2.合并data函数执行返回的数据对象

生命周期钩子会被保存进数组,权重较低的会优先执行,从全局mixin的声明周期到组件自身的生命周期

function mergeHook(parentVal, childVal) {    
    var arr;
    arr = childVal ?  
        // concat 不只可以拼接数组,什么都可以拼接
        ( parentVal ?    
            // 为什么parentVal 是个数组呢
            // 因为无论怎么样,第一个 parent 都是{ component,filter,directive}
            // 所以在这里,合并的时候,肯定只有 childVal,然后就变成了数组
            parentVal.concat(childVal) : 
            ( Array.isArray(childVal) ? childVal: [childVal] )
        ) :
        parentVal  
    return arr

}

components, directives, filters的原型叠加

strats.components=
strats.directives=
strats.filters = function mergeAssets(
    parentVal, childVal, vm, key
) {    
    var res = Object.create(parentVal || null);    
    if (childVal) { 
        for (var key in childVal) {
            res[key] = childVal[key];
        }   
    } 
    return res
}

watch的处理,也是合并成数组,重要的是合并顺序,跟生命周期的钩子一样

props, methods, computed这几个不允许重名,可以直接采用覆盖的方式,将权重高的覆盖权重较低的

strats.props = 
strats.methods = 
strats.inject = 
strats.computed = function(parentVal, childVal, vm, key) {    
    if (!parentVal) return childVal
    var ret = Object.create(null);   
    // 把 parentVal 的字段 复制到 ret 中
    for (var key in parentVal) {
       ret[key] = parentVal[key];
    }    
    if (childVal) {        
        for (var key in childVal) {
           ret[key] = childVal[key];
        }
    }    
    return ret

};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值