一,前言
上篇,介绍了 Vue 组件与初始化流程,涉及以下几部分:
- 组件使用介绍:全局组件、局部组件的定义和优先级;
- 组件初始化流程介绍:Vue.component、Vue.extend、保存组件构造函数、组件合并、初渲染和更新;
本篇,主要介绍 Vue.component 的实现;
二,Vue.component 实现
1,Vue.component 如何加载
Vue.component
是一个全局 API;
在 Vue
初始化流程中,通过 initGlobalAPI
方法,对全局 API 进行初始化操作;
// src/index.js
/**
* 在 vue 中所有的功能都通过原型扩展(原型模式)的方式来添加
* @param {*} options vue 实例化传入的配置对象
*/
function Vue(options) {
this._init(options);
}
initMixin(Vue)
renderMixin(Vue)
lifeCycleMixin(Vue)
initGlobalAPI(Vue) // 初始化 global Api
export default Vue;
在 initGlobalAPI
方法中,处理 Vue Global API
:
// src/global-api/index.js
export function initGlobalAPI(Vue) {
// 全局属性:Vue.options
// 功能:用于存放属性 mixin, component, filter, 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) {
// todo ...
}
}
2,Vue.component 如何定义
// Vue.component 全局 API 的定义
Vue.component = function (id, definition) {}
// Vue.component 全局 API 的使用
Vue.component('my-button', {
name:'my-button',
template:'<button>全局组件</button>'
})
2.1 组件名 name
每个组件都拥有一个唯一的组件名称,即组件的唯一标识;
- 组件名称默认使用
Vue.component
的第一个参数id
; - 若
definition
中包含name
属性,则使用name
属性值作为组件名;
代码实现:
/**
* Vue.component
*
* @param {*} id 组件名
* @param {*} definition 组件定义
*/
Vue.component = function (id, definition) {
// 获取组件名 name:优先使用 definition.name,默认使用 id
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)
}
// 若参入 definition 不是对象(是函数),不处理
}
Vue.extend
的作用:使用基础的 Vue 构造器,创建出一个子类;
下篇进行详细介绍:【Vue2.x 源码学习】第三十六篇 - Vue.extend 实现
3,组件构造函数的全局保存
在 initGlobalAPI
方法中,Vue.options
用于存放全局属性;
- 全局属性,会在每个组件初始化时,被合并到组件上;
- 在全局组件中,也会使用全局属性;
所以,全局组件也要注册到Vue.options
上;
这就需要对 Vue.options
对象进行扩展,构造 Vue.options.components
用于存放全局组件(将全局组件注册到 Vue.options
上):
// src/global-api/index.js
export function initGlobalAPI(Vue) {
// 全局属性:Vue.options
// 功能:存放 mixin, component, filter, directive 属性
Vue.options = {}; // 每个组件初始化时,将这些属性放入组件
// 用于存放全局组件
Vue.options.components = {};
/**
* 使用基础的 Vue 构造器,创造一个子类
*
* @param {*} definition
*/
Vue.extend = function (definition) {
// todo ...
}
/**
* 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
标签,能够快速、直接地查找到该组件的构造函数,并进行组件的实例化;
4,Vue.component 总结
Vue.component
是Vue Global API
;- 通过调用
Vue.component
进行全局组件声明; - 在
Vue.component
方法内部,当第二个参数组件定义definition
为对象时,会通过Vue.extend
处理并生成子类,即组件的构造函数; - 将组件名与组件构造函数的映射关系维护到
Vue.options.components
,提供后续组件合并与组件实例化使用;
三、结尾
本篇,主要介绍了 Vue 初始化流程中 Vue.component 的实现:
- Vue.component 全局 API 的初始化处理;
- Vue.component 的定义和参数说明;
- 组件构造函数全局存储的方式和作用;
下篇,Vue.extend 实现;
维护日志
- 20210809:
- 修改拼写错误的方法名;
- 微调文章排版;
- 20210811:
- 添加“组件定义 definition” 两种的代码示例;
- 调整部分描述语句,使语义更加贴切易懂;
- 微调部分排版顺序,使文字与代码示例之间关系层级明确清晰;
- 添加“Vue.component 总结”部分
- 20230223:
- 添加内容中的代码和关键字高亮;
- 优化部分内容描述,使表达更加清晰易懂;
- 调整了部分代码注释和格式,使逻辑更好理解;
- 更新文章概要;
- 20230303:
- 重新阅读本篇,梳理并调整了部分内容的描述,使表述和语义更加准确,更好理解;