5.1 组件两种注册方式
熟悉Vue的开发流程的都知道,Vue组件在使用之前需要进行注册,而注册的方式有两种,全局注册和局部注册。在进入源码分析之前,我们先回忆一下两者的用法,以便后续掌握两者的差异。
5.1.1 全局注册
Vue.component('my-test', {
template: '<div>{{test}}</div>',
data () {
return {
test: 1212
}
}
})
var vm = new Vue({
el: '#app',
template: '<div id="app"><my-test><my-test/></div>'
})
其中组件的全局注册需要在全局实例化Vue前调用,注册之后可以用在任何新创建的 Vue 实例的模板中调用。
5.1.2 局部注册
var myTest = {
template: '<div>{{test}}</div>',
data () {
return {
test: 1212
}
}
}
var vm = new Vue({
el: '#app',
component: {
myTest
}
})
当只需要在某个局部用到某个组件时,可以使用局部注册的方式进行组件注册,此时局部注册的组件只能在注册该组件的组件内部使用。
5.1.3 注册过程
简单回顾两种组件注册方式后,我们来看注册过程到底发生了什么,我们以全局组件注册为例。它通过Vue.component(name, {…})
进行组件注册,Vue.component
的定义在Vue
源码的初始化中。
// 初始化全局api
initAssetRegisters(Vue);
var ASSET_TYPES = [
'component',
'directive',
'filter'
];
function initAssetRegisters(Vue){
// 定义ASSET_TYPES中每个属性的方法,其中包括component
ASSET_TYPES.forEach(function (type) {
// type: component,directive,filter
Vue[type] = function (id,definition) {
if (!definition) {
// 直接返回注册组件的构造函数
return this.options[type + 's'][id]
}
...
if (type === 'component') {
// 验证component组件名字是否合法
validateComponentName(id);
}
if (type === 'component' && isPlainObject(definition)) {
// 组件名称设置
definition.name = definition.name || id;
// Vue.extend() 创建子组件,返回子类构造器
definition = this.options._base.extend(definition);
}
// 为Vue.options 上的component属性添加将子类构造器
this.options[type + 's'][id] = definition;
return definition
}
});
}
源码中全局注册组件的实际是调用构造函数Vue
的静态方法extend
,并且为Vue.options
上的component
属性添加子类构造器。其中extend方法的定义我们在深入剖析Vue源码 - 选项合并(上)中的子类构造器一段中有介绍这里不赘述,总结而言:Vue.extend
创建了一个基于父Vue的子类,创建过程会继承父类的方法,并对父类子类的配置进行合并,最终返回一个子类的构造器。这个子组件的名称默认以Vue.component()
的第一个参数作为组件名,当组件选项有name属性时,则用name属性覆盖。当Vue.component()
不传递第二个选项参数时,会返回已经注册过的子类构造器。
接下来留下一个问题,局部注册和全局注册的在实现上的区别在哪里?