关于javascript:Vuecomponent-怎么实现全局注册的

3次阅读

共计 2646 个字符,预计需要花费 7 分钟才能阅读完成。

最近在 React 我的项目中用到了公司官网的图标库。以前在 Vue 我的项目外面应用图标库采纳全局注册的形式,这样组件外面能够间接应用图标组件,无需手动 import 而后再注册组件。然而当初的 React 没方法像 Vue 一样实现全局注册,只能手动 import。所以我就很好奇,Vue 到底怎么实现全局注册的。

在之前的我的项目中,看到过有这种用法:

Vue.prototype.$axios = axios;

在下面代码中,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.componentVue.directiveVue.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 官网文档

正文完
 0