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
};