Vue源码学习(十一)全局组件和局部组件的注册

注册

Vue中组件注册分为全局注册和局部注册

全局注册
Vue.component('my-component-name', { /* ... */ })
  • 组件名 'my-component-name'
  • 配置项 { /* ... */ }
局部注册
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

无论时全局组件还是局部组件一定要注册后才能使用。

Vue.component

src/core/global-api/assets.js中,initAssetRegisters方法遍历ASSET_TYPES,并定义相关方法

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
      }
    }
  })
}


// src/shared/constants.js
export const ASSET_TYPES = [
  'component',
  'directive',
  'filter'
]

也就是说通过initAssetRegisters方法,给Vue构造函数添加了component,directive,filter方法,而initAssetRegisters会在src/core/global-api/index.js中的initGlobalAPI中进行调用。通过

 this.options[type + 's'][id] = definition

把定义的全局组件添加到Vue.options.components对象上。

可以看到Vue.component接受两个参数,id为字符串类型,可以作为第二个参数definitionname属性。重点看看下面这句代码

 definition = this.options._base.extend(definition)

上面这行代码等价于

 definition = Vue.extend(definition)

从前面的文章分析中我们知道,Vue.extend最终会返回组件构造器函数,并且在extend方法中调用mergeOptions方法对配置进行合并。

Sub.options = mergeOptions(
  Super.options,
  extendOptions
)

在组件实例化的时候,在initInternalComponent方法中进行配置合并

const opts = vm.$options = Object.create(vm.constructor.options)

也就是说此时vm.$options.components的对象中包含了我们定义的全局组件。
比如vm.$options.components['my-component-name'] = definition

在创建组件vnode的过程中,_createElement方法中会执行以下逻辑

Ctor = resolveAsset(context.$options, 'components', tag)

我们看看resolveAsset方法

// src/core/util/options.js
/**
 * Resolve an asset.
 * This function is used because child instances need access
 * to assets defined in its ancestor chain.
 */
export function resolveAsset (
  options: Object,
  type: string,
  id: string,
  warnMissing?: boolean
): any {
  /* istanbul ignore if */
  if (typeof id !== 'string') {
    return
  }
  const assets = options[type]
  // check local registration variations first
  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]
  // fallback to prototype chain
  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]拿到当前实例vm.$options对象上的components
  • 然后判断tag是否存在于components对象中,在判断的过程中,首先用传入的参数进行判断,如果没有尝试将tag转化为驼峰,最后转化为首字母大写进行组件是否存在判断。

如果resolveAsset方法有返回值,在_createElement方法中接着调用createComponent方法生成为组件vnode

通过上面的分析,我们应该可以了解到Vue.component注册全局组件背后的机制,这里进行了多次merge options,首先将Vue.options合并到子类的Super.options对象上,在组件实例化的时候,还会进行配置项的合并,最终在组件实例的vm.$options属性上存在着components对象,而components中有我们定义的全局组件

局部注册

components:{
	'component-a': ComponentA,
    'component-b': ComponentB
}

通过前面的文章分析我们可以清楚的了解到局部注册这种方式在组件实例的vm.$options.components对象上有我们定义的局部组件

小结

全局注册和局部注册其实实现思路一致,都是通过配置合并保证在组件实例的$options对象上有我们定义的全局或局部组件,以确保能通过resolveAsset方法,最终调用createComponent方法生成组件vnode

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值