vue中有两种组件的注册方式
分别是全局和局部
全局注册
Vue.component('组件名', {
})
例子
Vue.component('com', {
name: 'com',
mounted(){},
render(c) {
return c('div', {}, '我是全局组件')
}
})
然后就可以在全局使用<com></com> 或者 <com/>进行使用了
Vue.component定义在src/core/global-api/assets.js
export function initAssetRegisters (Vue: GlobalAPI) {
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
...
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
}
ASSET_TYPES 定义在 src/shared/constants.js 中:
export const ASSET_TYPES = [
'component',
'directive',
'filter'
]
组件的创建都是通过 Vue.extend 继承的
继承过程中有合并配置的处理
Sub.options = mergeOptions(
Super.options,
extendOptions
)
它会把 Vue.options 合并到 Sub.options,
然后在组件的实例化阶段,
会执行 _init方法通过initInternalComponent函数
把 Sub.options.components 合并到 vm.$options.components 上。
创建 vnode 的过程中,会执行 _createElement 方法
有一个判定
else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
resolveAsset 的定义,在 src\core\util\options.js 中:
export function resolveAsset (
options: Object,
type: string,
id: string,
warnMissing?: boolean
): any {
if (typeof id !== 'string') {
return
}
const assets = options[type]
if (hasOwn(assets, id)) return assets[id]
const camelizedId = camelize(id)
if (hasOwn(assets, camelizedId)) return assets[camelizedId]
const PascalCaseId = capitalize(camelizedId)
if (hasOwn(assets, PascalCaseId)) return assets[PascalCaseId]
const res = assets[id] || assets[camelizedId] || assets[PascalCaseId]
if (process.env.NODE_ENV !== 'production' && warnMissing && !res) {
warn(
'Failed to resolve ' + type.slice(0, -1) + ': ' + id,
options
)
}
return res
}
先通过 const assets = options[type] 拿到 assets,
再尝试拿 assets[id],使用 id 拿,如果不存在,
则把 id 变成驼峰的形式再拿,如果仍然不存在则在驼峰的基础上把首字母再变成大写的形式再拿,
如果仍然拿不到则报错。
我们使用时最后注册的是什么名字就用什么名字,这样会减少判断,优化一些速度
局部注册
import xx from 'xx'
export default {
components: {
xx
}
}
原理和全局注册差不多
局部注册和全局注册不同的是,只有父组件才可以访问局部注册的子组件,
全局注册是挂到 Vue.options 下,所有组件实例化执行_init方法,
都会从全局的 Vue.options.components 扩展到当前组件的 vm.$options.components 下
所以全局组件可以在到处直接使用
例子
全局注册了组件D
一个组件B什么都没注册
一个组件C局部注册了A组件
实例化后最终
B的components
{
D
}
C的components
{
A,
D
}
也就是说B和A都能使用D,但是只有C可以使用A