【手写 Vue2.x 源码】第三十五篇 - 组件部分 - Vue.component 实现

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

一前言

上篇介绍了 Vue 组件与初始化流程涉及以下几部分

  • 组件使用介绍包括组件定义和优先级
  • 组件的初始化流程介绍包括Vue.component、Vue.extend、全局组件构造函数保存、组件层级关系维护、组件合并、组件的渲染和更新

本篇主要介绍 Vue.component


二Vue.component 实现

1Vue.component 如何加载

Vue.component 是全局 API

在 Vue 初始化 init 时会对全局 API 做集中处理

// src/index.js

/**
 * 在vue 中所有的功能都通过原型扩展原型模式的方式来添加
 * @param {*} options vue 实例化传入的配置对象
 */
function Vue(options) {
    this._init(options);  // 调用Vue原型上的方法_init
}

initMixin(Vue)
renderMixin(Vue)
lifeCycleMixin(Vue)
initGlobalAPI(Vue) // 初始化 global Api

export default Vue;

initGlobalAPI 方法处理全局 API

// src/global-api/index.js

export function initGlobalAPI(Vue) {
  // 全局属性Vue.options
  // 功能存放 mixin, component, filte, directive 属性
  Vue.options = {}; 
  
  Vue.mixin = function (options) {
    this.options = mergeOptions(this.options, options);
    return this;  // 返回this,提供链式调用
  }
  
  /**
   * Vue.component API
   * @param {*} id          组件名
   * @param {*} definition  组件定义
   */
  Vue.component = function (id, definition) {
    
  }
}

2Vue.component 如何定义

// 方法定义
Vue.component = function (id, definition) {}
  
// 使用方式
Vue.component('my-button',{
  name:'my-button',
  template:'<button>全局组件</button>'
})

2.1 组件名 name

每个组件都有一个自己的名字即组件的唯一标识

  • 默认组件名是id即 Vue.component 的第一个参数
  • 若 definition 中有 name使用 name 值作为组件名
/**
  * Vue.component
  * @param {*} id          组件名
  * @param {*} definition  组件定义
  */
Vue.component = function (id, definition) {
  definition.name = definition.name || id;
}

2.2 组件定义 definition

Vue.component 的第二个参数 definition即组件定义

组件定义 definition 即可以是函数也可以是对象

  • Vue.extend({ /* … */ }
  • { /* … */ }
// 写法 1注册组件传入一个扩展过的构造器 
Vue.component('my-component', Vue.extend({ /* ... */ })) 

// 写法 2注册组件传入一个选项对象 (自动调用 Vue.extend) 
Vue.component('my-component', { /* ... */ }) 

// 获取注册的组件 (始终返回构造器) 
var MyComponent = Vue.component('my-component')

若入参 definition 为对象则在 Vue.component 方法内部会使用 Vue.extend 进行一次处理

// src/global-api/index.js

/**
  * 使用基础的 Vue 构造器创造一个子类
  * @param {*} definition
  */
Vue.extend = function (definition) {

}

/**
  * Vue.component
  * @param {*} id          组件名
  * @param {*} definition  组件定义对象或函数
  */
Vue.component = function (id, definition) {
  // 获取组件名 name:优先使用definition.name默认使用 id
  let name = definition.name || id;
  definition.name = name;

  // 如果传入的 definition 是对象需要用 Vue.extend 包裹
  if(isObject(definition)){
    definition = Vue.extend(definition)
  }
}

Vue.extend使用基础的 Vue 构造器创建一个子类

下篇进行详细介绍【Vue2.x 源码学习】第三十六篇 - Vue.extend 实现

3组件构造函数的全局保存

在 initGlobalAPI 方法中Vue.options 用于存放全局属性而在全局组件中也会使用全局属性所以全局组件也要注册到 Vue.options 上

所以扩展Vue.options对象 Vue.options.components 用于存放全局组件

// src/global-api/index.js

export function initGlobalAPI(Vue) {
  // 全局属性Vue.options
  // 功能存放 mixin, component, filte, directive 属性
  Vue.options = {}; // 每个组件初始化时将这些属性放入组件
  // 用于存放全局组件
  Vue.options.components = {};
  
  /**
   * 使用基础的 Vue 构造器创造一个子类
   * @param {*} definition 
   */
  Vue.extend = function (definition) {
    
  }
  
  /**
   * Vue.component
   * @param {*} id          组件名默认
   * @param {*} definition  组件定义可能是对象或函数
   */
  Vue.component = function (id, definition) {

    // 获取组件名 name:优先使用definition.name默认使用 id
    let name = definition.name || id;
    definition.name = name;

    // 如果传入的 definition 是对象需要用 Vue.extend 包裹
    if(isObject(definition)){
      definition = Vue.extend(definition)
    }

    // 将 definition 对象保存到全局Vue.options.components
    Vue.options.components[name] = definition;

  }
}

Vue.options.components 就相当于在全局维护了一个组件名与组件构造函数的映射关系

这样做的目的和作用

  • 便于后续通过全局上的vm.constructor.options进行全局、局部组件的合并
  • 便于后续根据组件虚拟节点的 tag 标签能够直接查找到该组件的构造函数并进行组件的实例化

4Vue.component 总结

  • Vue.component 是 Vue Global API
  • 通过调用 Vue.component 进行全局组件声明
  • 在 Vue 初始化时Vue.component 内部通过 Vue.extend 生成子类即组件的构造函数
  • 维护组件名与组件构造函数的映射关系到Vue.options.components 供后续组件合并与组件实例化使用

三、结尾

备注对组件初始化流程中的 Vue.component API 单独进行介绍因此内容可能会上下不连贯还会有一些遗漏下周继续写组件初始化流程过程中再持续进行补充和完善

本篇主要介绍了 Vue 初始化流程中的 Vue.component 实现

  • Vue.component 全局 API 的初始化处理
  • Vue.component 的定义和参数说明
  • 组件构造函数全局存储的方式和作用

下篇Vue.extend 实现


维护日志

  • 20210809
    • 修改拼写错误的方法名
    • 微调文章排版
  • 20210811
    • 添加“组件定义 definition” 两种的代码示例
    • 调整部分描述语句使语义更加贴切易懂
    • 微调部分排版顺序使文字与代码示例之间关系层级明确清晰
    • 添加“Vue.component 总结”部分
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue