前面花了两节的内容介绍了组件,从组件的原理讲到组件的应用,包括异步组件和函数式组件的实现和使用场景。众所周知,组件是贯穿整个Vue设计理念的东西,并且也是指导我们开发的核心思想,所以接下来的几篇文章,将重新回到组件的内容去做源码分析,首先会从常用的动态组件开始,包括内联模板的原理,最后会简单的提到内置组件的概念,为之后的文章埋下伏笔。
12.1 动态组件
动态组件我相信大部分在开发的过程中都会用到,当我们需要在不同的组件之间进行状态切换时,动态组件可以很好的满足我们的需求,其中的核心是component
标签和is
属性的使用。
12.1.1 基本用法
例子是一个动态组件的基本使用场景,当点击按钮时,视图根据this.chooseTabs
值在组件child1,child2,child3
间切换。
// vue
<div id="app">
<button @click="changeTabs('child1')">child1</button>
<button @click="changeTabs('child2')">child2</button>
<button @click="changeTabs('child3')">child3</button>
<component :is="chooseTabs">
</component>
</div>
// js
var child1 = {
template: '<div>content1</div>',
}
var child2 = {
template: '<div>content2</div>'
}
var child3 = {
template: '<div>content3</div>'
}
var vm = new Vue({
el: '#app',
components: {
child1,
child2,
child3
},
methods: {
changeTabs(tab) {
this.chooseTabs = tab;
}
}
})
12.1.2 AST解析
<component>
的解读和前面几篇内容一致,会从AST
解析阶段说起,过程也不会专注每一个细节,而是把和以往处理方式不同的地方特别说明。针对动态组件解析的差异,集中在processComponent
上,由于标签上is
属性的存在,它会在最终的ast
树上打上component
属性的标志。
// 针对动态组件的解析
function processComponent (el) {
var binding;
// 拿到is属性所对应的值
if ((binding = getBindingAttr(el, 'is'))) {
// ast树上多了component的属性
el.component = binding;
}
if (getAndRemoveAttr(el, 'inline-template') != null) {
el.inlineTemplate = true;
}
}
最终的ast
树如下:
12.1.3 render函数
有了ast
树,接下来是根据ast
树生成可执行的render
函数,由于有component
属性,render
函数的产生过程会走genComponent
分支。
// render函数生成函数
var code = generate(ast, options);
// generate函数的实现
function generate (ast,options) {
var stat