Vue.component|Vue.component 怎么实现全局注册的
最近在 React 项目中用到了公司官方的图标库。以前在 Vue 项目里面使用图标库采用全局注册的方式,这样组件里面可以直接使用图标组件,无需手动 import
然后再注册组件。但是现在的 React 没办法像 Vue 一样实现全局注册,只能手动 import
。所以我就很好奇,Vue 究竟怎么实现全局注册的。
在之前的项目中,看到过有这种用法:
Vue.prototype.$axios = axios;
【Vue.component|Vue.component 怎么实现全局注册的】在上面代码中,
axios
被挂载到了 Vue
原型对象上面,这样在每一个组件实例中都可以通过 this.$axios
访问到 axois
,也就是实现了全局注册。看源码之前,可以大胆猜测一下,组件全局注册应该是把组件挂载到了 Vue 构造器上面,这样创建的每一个 Vue 实例,里面的
$options
都包含了这个组件,因此就可以直接使用。Vue.component 是怎么使用的 看源码之前,先看看官方文档的描述,这样更容易理解。
// {String} id
// {Function | Object} [definition]
Vue.component( id, [definition] )
这个 api 的作用是注册或获取全局组件。注册还会自动使用给定的 id 设置组件的名称。
// 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })// 获取注册的组件 (始终返回构造器)
var MyComponent = Vue.component('my-component')
源码解析
Vue.component
的源码在这个目录下:node_modules\vue\src\core\global-api\assets.js但是看源码之前,先看下
global-api\index.js
。这部分主要是初始化 Vue
构造函数,在上面挂载各种全局 api 。然后在第 54 行,有这样一段代码:Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
这里的作用是在
Vue
上面初始化一个 options
对象,然后对象的 key 来自于这里:export const ASSET_TYPES = [
'component',
'directive',
'filter'
]
这段代码执行完应该可以得到这个:
Vue.options = {
components: {},
directives: {},
filters: {}
}
然后接着在
global-api\index.js:68
有这样一段代码:initAssetRegisters(Vue)
initAssetRegisters
函数就定义在 global-api\assets.js
里面,一起来看下:import { ASSET_TYPES } from 'shared/constants'
import { isPlainObject, validateComponentName } from '../util/index'export function initAssetRegisters (Vue: GlobalAPI) {
/**
* Create asset registration methods.
*/
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id)
}
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
}
}
})
}
从这里可以看出,
Vue.component
,Vue.directive
和 Vue.filter
都共用一套代码,但我们这里只关心 Vue.component
。我们先来看函数的入参,按照文档的描述,
Vue.component
第一个参数 id
是组件名,第二个参数 definition
可以是一个选项对象,或者一个构造器。然后来看下这段代码:
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
这段代码的意思就是,
Vue.component
如果传入的是一个选项对象,那么就调用 extend
方法转为构造器,这与官方文档描述一致。然后这段代码将构造器挂载到
Vue.options
上面:this.options[type + 's'][id] = definition
挂载完成之后,应该会得到下面的结果:
Vue.options = {
components: {
/* Vue 一些内置组件,例如 keep-alive 也会挂载到这里 */
'custom-component': VueComponent(options)
},
directives: {},
filters: {}
}
到这里答案应该很明确了,
Vue.component
通过把自定义组件挂载到 Vue.options.components
里面,从而实现全局注册。参考 Vue.component - Vue 官方文档
推荐阅读
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- 七年之痒之后
- 开花店的前景怎么样()
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- MybatisPlus使用queryWrapper如何实现复杂查询
- python学习之|python学习之 实现QQ自动发送消息
- 私通和背叛,他怎么看(——晨读小记)
- 有句话忍很久了,女生要求买房怎么就物质了()
- 孩子不是实现父母欲望的工具——林哈夫
- opencv|opencv C++模板匹配的简单实现