组件注册的使用场景有两种: , 全局注册 局部注册 局部组件与全局的组件的区别 全局组件是扩展到 Vue.options 下,所有组件创建的过程中,都会从全局的 Vue.options.components 扩展到当前组件的 vm.$options.components,这就是全局组件能在全局使用的原因,局部注册是注册在 Sub.option 扩展。

组件注册的使用场景有两种:全局注册,局部注册

全局注册

// 这是一个全局注册的例子
Vue.component('my-component', {
  // 选项
});
// src/core/global-api/assets.js
export const ASSET_TYPES = ['component', 'directive', 'filter'];
export function initAssetRegisters(Vue: GlobalAPI) {
  // 遍历ASSET_TYPES 得到type后挂载到Vue上
  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);
        }
        // 如果type 是component 并且definition 是一个对象
        if (type === 'component' && isPlainObject(definition)) {
          definition.name = definition.name || id;
          // 相当于Vue.extend,把这个对象转换成一个继承于Vue的构造函数 this.options._base=Vue
          definition = this.options._base.extend(definition);
        }
        if (type === 'directive' && typeof definition === 'function') {
          definition = { bind: definition, update: definition };
        }
        // 然后挂载在Vue.options.components上
        // 每个组件的创建都是通过Vue.extend继承而来,最终将会把Vue.options合并到Sub.options,也就是组件options上
        // 然后在组件实例化阶段,会执行merge options,把Sub.options.components合并到vm.$options.components
        // 在创建vnode的过程中,会执行_creatElement方法
        this.options[type + 's'][id] = definition;
        return definition;
      }
    };
  });
}
// src/core/vdom/create-element.js
export function _createElement(context: Component, tag?: string | Class<Component> | Function | Object, data?: VNodeData, children?: any, normalizationType?: number): VNode | Array<VNode> {
  // ...
  let vnode, ns;
  if (typeof tag === 'string') {
    let Ctor;
    ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag);
    if (config.isReservedTag(tag)) {
      // 创建一个普通vnoode
      vnode = new VNode(config.parsePlatformTagName(tag), data, children, undefined, undefined, context);
      //在执行完resolveAsset后,拿到组件的构造函数
    } else if (isDef((Ctor = resolveAsset(context.$options, 'components', tag)))) {
      // 作为createComponent 的钩子的参数
      vnode = createComponent(Ctor, data, context, children, tag);
    } else {
      // 创建一个不认识的vnode
      vnode = new VNode(tag, data, children, undefined, undefined, context);
    }
  } else {
    // direct component options / constructor
    vnode = createComponent(tag, data, context, children);
  }
  // ...
}
// 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;
  }
  // 先获取到assets type为components
  const assets = options[type];
  // 再获取到assets[id]
  if (hasOwn(assets, id)) return assets[id];

  const camelizedId = camelize(id);

  // 如果id不存在,把id变成驼峰形式
  if (hasOwn(assets, camelizedId)) return assets[camelizedId];
  const PascalCaseId = capitalize(camelizedId);
  // 如果还不存在,就查一下驼峰基础上首字母也大写看存在不
  if (hasOwn(assets, PascalCaseId)) return assets[PascalCaseId];
  // 如果还不存在,就从原型中找
  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;
}

局部注册

// vue实例化时合并option,把component合并到vm.$options.components上
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.cid = cid++;
Sub.options = mergeOptions(Super.options, extendOptions);
// 这时候就能在resolveAsset的时候拿到组件的构造函数,作为createComponent的钩子参数
// 局部注册的核心是:初始化合并option,拿到组件的构造函数,然后createElement
import HelloWorld from './components/HelloWorld';

export default {
  components: {
    HelloWorld
  }
};

局部组件与全局的组件的区别

全局组件是扩展到 Vue.options 下,所有组件创建的过程中,都会从全局的 Vue.options.components 扩展到当前组件的 vm.$options.components,这就是全局组件能在全局使用的原因,局部注册是注册在 Sub.option 扩展。

暂无评论