mergeOptions
将2个配置选项合并到一个新的对象中
function mergeOptions ( parent, child,vm) {
// 校验组件名是否符合规范,不能与 标签名和svg 名称重名
if (process.env.NODE_ENV !== 'production') {
checkComponents(child)
}
// 合并的 child 是一个子类构造函数时,就取出它的options
if (typeof child === 'function') {
child = child.options
}
// 格式化 props、inject、directive
normalizeProps(child, vm)
normalizeInject(child, vm)
normalizeDirectives(child)
// 如果 child 有 extends 和 mixins 配置则合并它们
// 合并过配置的child 上会有 _base属性,所以无需再次合并
if (!child._base) {
if (child.extends) {
parent = mergeOptions(parent, child.extends, vm)
}
if (child.mixins) {
for (let i = 0, l = child.mixins.length; i < l; i++) {
parent = mergeOptions(parent, child.mixins[i], vm)
}
}
}
// 开始合并配置.下文有链接专门介绍合并过程
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
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
normalizeProps
格式化 props 的格式
function normalizeProps (options, vm) {
const props = options.props
// 没有配置 props 时直接跳出
if (!props) return
// 设置一个新的对象来保存格式化后的props
const res = {}
let i, val, name
/*
* 如果提供的是 Array格式的 props,依次遍历把数据格式化成
* props: {
key: {type: null}
* }
*/
if (Array.isArray(props)) {
i = props.length
while (i--) {
val = props[i]
if (typeof val === 'string') {
name = camelize(val)
res[name] = { type: null }
}
}
} else if (isPlainObject(props)) {
/*
* 如果提供的是Object 类型,处理结果与Array类似
* props: {key: {type: Type}}
*/
for (const key in props) {
val = props[key]
name = camelize(key)
res[name] = isPlainObject(val)
? val
: { type: val }
}
}
options.props = res
}
normalizeInject
格式化传入的 inject 数据
function normalizeInject (options, vm) {
// 没有inject就退出
const inject = options.inject
if (!inject) return
const normalized = options.inject = {}
// 传入的inject 是Array的情况下,把数据格式化成
/*
{
key: { from: inject[key] }
}
*/
if (Array.isArray(inject)) {
for (let i = 0; i < inject.length; i++) {
normalized[inject[i]] = { from: inject[i] }
}
} else if (isPlainObject(inject)) {
// inject 是Object类型的时候,依次遍历属性
// 1. 值为Object格式,则合并对象中所有属性到一个新的对象中
// 2. 值为 String, 则格式化为 { from: val }
for (const key in inject) {
const val = inject[key]
normalized[key] = isPlainObject(val)
? extend({ from: key }, val)
: { from: val }
}
}
}
normalizeDirectives
格式化自定义指令
function normalizeDirectives (options: Object) {
const dirs = options.directives
if (dirs) {
// 传入的指令格式为Object,把每个指令都遍历出来,只处理传入了单一函数的指令
/*
directives: {
"v-demo": function(){...}
}
*/
for (const key in dirs) {
const def = dirs[key]
// 这里只是检查一下传入的指令是否只有一个函数
// 如果是的,那么就把bind和update同时指向这个函数
// 否则就无需格式化
if (typeof def === 'function') {
dirs[key] = { bind: def, update: def }
}
}
}
}
经过上面一系列格式化之后,开始合并配置 mergeField