一,前言
上篇,介绍了 Vue 组件与初始化流程,涉及以下几部分:
本篇,主要介绍 Vue.component;
二,Vue.component 实现
1,Vue.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) {
}
}
复制代码
2,Vue.component 如何定义
// 方法定义
Vue.component = function (id, definition) {}
// 使用方式
Vue.component('my-button',{
name:'my-button',
template:'<button>全局组件</button>'
})
复制代码
2.1 组件名 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
就相当于在全局维护了一个组件名与组件构造函数的映射关系;
这样做的目的和作用:
4,Vue.component 总结
Vue.component 是 Vue Global API;
通过调用 Vue.component 进行全局组件声明;
在 Vue 初始化时,Vue.component 内部通过 Vue.extend 生成子类,即组件的构造函数;
维护组件名与组件构造函数的映射关系到Vue.options.components
供后续组件合并与组件实例化使用;
三、结尾
备注:对组件初始化流程中的 Vue.component API 单独进行介绍,因此内容可能会上下不连贯,还会有一些遗漏,下周继续写组件初始化流程,过程中再持续进行补充和完善;
本篇,主要介绍了 Vue 初始化流程中的 Vue.component 实现:
下篇,Vue.extend 实现;
评论