【vue2源码学习】— 组件使用

vue中有两种组件的注册方式
分别是全局和局部

全局注册

Vue.component('组件名', {
  // 配置
})
例子
Vue.component('com', {
  name: 'com', // name拿来做组件名的优先级比Vue.component的第一个参数高
  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全局函数
    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)) {
        // 相当于 Vue.extend 把definition这个对象转换成一个继承于 Vue 的构造函数,
        // 最后通过 this.options[type + 's'][id] = definition 
        // 把它挂载到 Vue.options.components 上。
          definition.name = definition.name || id // 体现name的优先级
          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 {
  /* 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] 拿到 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值