Vue.component = function(id, definition) {
if (!definition) {
return this.options.components[id]
} else {
if (isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
this.options.components[id] = definition
return definition
}
}
简单解读一下就是:
如果 definition 不存在,说明此前被全局注册过,那就去 Vue.options.components 中找到对应的组件返回;
如果 definition 存在,说明这是一个新的全局组件,需要被全局注册。先判断 definition 是否是一个对象,如果是则将 definition 创建为继承自 Vue构造函数 的子类实例,如果不是则说明是一个已经继承自子类的实例,将其放置到 Vue.options.components 中,然后返回。
有一些绕,那我们就通过代码来进行说明:
// 方式1
const childComponent = Vue.extend({
data: {},
created() {},
methods: {},
})
Vue.component('child', childComponent)
// 方式2
Vue.component('child', {
name: 'child-component',
data: {},
created() {},
methods: {},
})
如果是方式1,那么这时候不会进入 isPlainObject(definition) 的判断,直接将 childComponent 放置到 this.options.components['child'] 中,然后将 childComponent 返回。
如果是方式2,那么这时候会进入 isPlainObject(definition) 的判断,当前 definition.name 有值且为 'child-component',definition 会继续走入
this.options._base.extend(definition),这个方法其实就是 Vue.extend,然后将继承自 Vue构造函数 的子类的实例返回给 definition,再将这个 definition 放置到 this.options.components['child-component'] 中,最后将 definition 返回。
通过这两种方式我们可以知道,通过 Vue.component(id, definition) 注册的组件都会经过一层 Vue.extend(definition) 的包装生成一个子类实例,我们取名为 componentVM ,然后将这个 componentVM 放入 Vue.options.components 中,最后返回 componentVM。
从 Vue.component 可以得知,组件化的核心其实是在于 Vue.extend,通过 Vue.extend 包装过后的实例才是真正的组件
Vue.extend = function (extendOptions) {
extendOptions = extendOptions || {}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) return cachedCtors[SuperId]
const name = extendOptions.name || Super.options.name
const Sub = function VueComponent (options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
Sub['super'] = Super
if (Sub.options.props) {
initProps(Sub)
}
if (Sub.options.computed) {
initComputed(Sub)
}
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
if (name) {
Sub.options.components[name] = Sub
}
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
cachedCtors[SuperId] = Sub
return Sub
}