TODO:
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
// 校验组件命名是否规范
if (process.env.NODE_ENV !== 'production') {
checkComponents(child)
}
// 如果 child 是另外一个构造函数则取其静态属性来进行合并
if (typeof child === 'function') {
child = child.options
}
// 格式化 Props 格式
// 最终形态为 {[p: string]: {type: Number | String | Boolean | Array | Object, default?: any }}
normalizeProps(child, vm)
// 格式化 inject
// 最终形态为 inject: {[p: string]: {from: string, [p: string]: string}}
normalizeInject(child, vm)
// 格式化 directives
// 最终形态为 directive: {bind?: Function, update?: Function}
normalizeDirectives(child)
// _base 的有无代表是否已经 merge 过
if (!child._base) {
// 如果是继承的实例/构造函数,则递归的向上合并所有 options
if (child.extends) {
parent = mergeOptions(parent, child.extends, vm)
}
// 若果有 mixins, 则遍历合并 mixins 中的 options
if (child.mixins) {
for (let i = 0, l = child.mixins.length; i < l; i++) {
parent = mergeOptions(parent, child.mixins[i], vm)
}
}
}
// 到此为止,除了 child 的 options 没合并外,父类和 mixins 的 options 均已合并
// 将 parent.options 和 child.options 中的交集通过 config.optionMergeStrategies 中的配置过的对应策略来合并,
// 比如 web 端的 el、propsData 如果两边都有就会报错,因为只有可能根节点, 通过 new Vue 的才有可能有需要有 el、propsData 配置
// 如果没有对应策略则优先取 child 的值
// 接着再将 child 中 parent 没有的合并到 options 中
const options = {}
let key
for (key in parent) {
mergeField(key)
}
for (key in child) {
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
function mergeField (key) {
const strat = strats[key] || defaultStrat
// 此处可能会没有 vm,没有 vm 意味着当前合并的场景并非 Vue 实例化,反之则是。
// 如果没有 vm,则一些特殊的合并策略则会得出不同的结果
// 比如
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
el、propsData 的合并策略
if (process.env.NODE_ENV !== 'production') {
strats.el = strats.propsData = function (parent, child, vm, key) {
if (!vm) {
warn(
`option "${key}" can only be used during instance ` +
'creation with the `new` keyword.'
)
}
return defaultStrat(parent, child)
}
}
由于 el、propsData 只有在 new Vue
的时候才会出现,所以如果没传了 vm
则意味着并非在 new Vue
的时候出现,则报错
data 的合并策略
strats.data = function (
parentVal: any,
childVal: any,
vm?: Component
): ?Function {
if (!vm) {
if (childVal && typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
)
return parentVal
}
return mergeDataOrFn(parentVal, childVal)
}
return mergeDataOrFn(parentVal, childVal, vm)
}
如果不是在实例化过程中,传的 child.data 不是函数则报错并且只返回 parent.data,反之则合并。
合并的规则是,如果不是在实例化过程中合并,则返回一个函数,该函数调用后则会调用返回 child.data 为优先的