Vue 组件全局注册和局部注册使用及原理

Vue在注册组件时有两种方式,全局注册局部注册
全局注册的话我们可以在任意组件中使用注册的组件,而局部注册的话我们只能在当前的组件中使用注册到的组件,

全局注册实例

Vue.component("app",App);

局部注册实例

components:{
      App
}

下面我们进入两种注册方式的源码实现,首先进入Vue.component

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

这里是对三种方法的定义'component', 'directive', 'filter',这里我们要说的是component,可以看到,当type = 'component时,直接调用了extend方法,extends 就是对Vue对象的扩展,就是一个组件的Vue构造函数,拥有Vue的所有方法,最后,将这个扩展赋值给了全局Vue 的options 的components 属性中,然后,我们进入到patch时 解析标签时的

let vnode, ns
  if (typeof tag === 'string') {
    let Ctor
    ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
    if (config.isReservedTag(tag)) {
      // platform built-in elements
      vnode = new VNode(
        config.parsePlatformTagName(tag), data, children,
        undefined, undefined, context
      )
    } else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
      // component
      vnode = createComponent(Ctor, data, context, children, tag)
    } else {
      // unknown or unlisted namespaced elements
      // check at runtime because it may get assigned a namespace when its
      // parent normalizes children
      vnode = new VNode(
        tag, data, children,
        undefined, undefined, context
      )
    }
  } else {
    // direct component options / constructor
    vnode = createComponent(tag, data, context, children)
  }

当标签类型为普通标签时,会创建普通类型的标签,如果不是普通标签时我们可以看else if里,Ctor = resolveAsset(context.$options, 'components', tag) 我们找到这个函数,定义在源码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
}

这里的options是 Vue构造函数的options和当前组件options的组合,这里是重点,,这个options是由之前调用的extends 方法完成合并的,,这也是全局组件和局部组件的区别所在,可以看到代码中是通过这个options 对象来找 注册的组件,三个if是对驼峰式和大写式查找的支持,因为之前的component方法定义中已经将这个全局注册的组件的名字放到了Vue构造函数的options中,所以在这里可以通过组合的options[组建名称]查找到对应的组件构造函数,因为这个options包含Vue构造函数options和本组件的options,所以在任何地方都可以使用全局注册的组件,而局部注册的组件只会在局部组件的配置合并中合并到局部options中,当在其他组件的options中寻找注册的组件时就会找不到,所以局部注册的组件只存在于局部options中,下面我们看下局部options的合并

export function initInternalComponent (vm: Component, options: InternalComponentOptions) {
  const opts = vm.$options = Object.create(vm.constructor.options)
  // doing this because it's faster than dynamic enumeration.
  const parentVnode = options._parentVnode
  opts.parent = options.parent
  opts._parentVnode = parentVnode

  const vnodeComponentOptions = parentVnode.componentOptions
  opts.propsData = vnodeComponentOptions.propsData
  opts._parentListeners = vnodeComponentOptions.listeners
  opts._renderChildren = vnodeComponentOptions.children
  opts._componentTag = vnodeComponentOptions.tag

  if (options.render) {
    opts.render = options.render
    opts.staticRenderFns = options.staticRenderFns
  }
}

这里是局部组件options 合并的代码,局部注册的components属性便会合并到options中,所以在当前templete中的component标签便可以在此组件的options中找到对应的构造函数从而构造出对应的组件vnode。
所以 options就是组件的构造函数的属性包括data啊,computed啊,props啊,component那些,因为组件树的底层options都会包含Vue构造函数options,所以,在Vue中注册的component可以在任何地方访问到,

你可能感兴趣的:(Vue 组件全局注册和局部注册使用及原理)