parse
processIf用于处理v-if:
1 | function processIf(el) { |
我们照常用一个示范html帮助理解:
1 | <div id="app"> |
上面这段html会调用processIf3 次,每次的差别在于attrsMap里的属性值:
1 | { |
都处理完后,el上会多出 3 个属性值:
1 | { |
addIfCondition用于给el.ifConditions数组塞入新元素:
1 | export function addIfCondition(el: ASTElement, condition: ASTIfCondition) { |
细心的人可能发现了只有if分支才改变了el.ifConditions,另外两个分支应该也会有类似的操作,在什么地方做的呢?
在调用完processIf后,还有一个地方调用了processIfConditions,它也会操作el.ifConditions:
1 | if (currentParent && !element.forbidden) { |
很明显我们在处理到v-else-if和v-else时,processIfConditions都会被调用。另外注意这种情况下是不会把当前元素计入currentParent.children的,只有v-if节点才被计入了。看看processIfConditions:
1 | function processIfConditions(el, parent) { |
findPrevElement用来在前面找到紧挨着v-else-if和v-else的那个节点:
1 | // 找到children中第一个element节点 |
最终经过parse处理,我们的AST节点上就有了所有分支的相关属性:
1 | { |
注意根节点的children只有一个元素,这与我们上面讲的一致,只有v-if才进入了父元素的children中。Vue template的一个细节就是有这个处理得出的,后面会说。
generate
处理v-if的是genIf函数:
1 | export function genIf(el: any, state: CodegenState, altGen?: Function, altEmpty?: string): string { |
注释很详细,我们直接看最终生成的render字符串:
1 | ` |
没有涉及新的帮助函数,可以很清楚的看到核心是一个嵌套的三目运算,最终只有条件成立的那个分支才会生成对应的vnode
。
template 小细节
通常情况下,我们的Vue组件只能有一个根元素,但是使用v-if可以有多个根元素分支:
1 | <div id="app"> |
正是因为parse阶段处理v-if时的特殊代码:
1 | if (!root) { |
currentParent的children中只会有v-if分支的节点,v-else-if、v-else节点都会放到el.ifConditions中,只在条件成立时才渲染出来。