前言有时候在一些面试中,经常会被问到v-for和v-if哪个优先。下面我们就通过分析源码来回答这个问题。下面的内容是基于《当我们在谈论v-model时,我们在谈论什么?从下面的例子继续分析:newVue({el:'#app',template:`
`})从上一篇文章我们可以知道编译分为三个步骤:parse:解析模板字符串生成AST语法树optimize:优化语法树,主要是在标记静态节点提高更新页面性能时在parseparse过程中,使用了大量的正则表达式来解析模板。开头的例子会被解析成如下的AST节点://其实ast有很多属性,我这里只展示涉及到解析的属性ast={'type':1,'tag':'ul','attrsList':[],attrsMap:{},'children':[{'type':1,'tag':'li','attrsList':[],'attrsMap':{'v-for':'(item,index)indata','v-if':'index!==0'},//v-if解析属性'if':'index!==0','ifConditions':[{'exp':'index!==0','block'://指向el本身}],//v-for解析的属性'for':'items','alias':'item','iterator1':'index','parent'://指向其父节点'children':['type':2,'expression':'_s(item)''text':'{{item}}','tokens':[{'@binding':'item'},]]}]}对于v-for命令,除了记录在attrsMap和attrsList中外,for(对应待处理的对象或数组traversed),别名,iterator1,iterator2分别对应v-for指令绑定内容中的第一、二、三参数。开头的例子没有第三个参数,所以没有iterator2属性。对于v-if指令,将v-if指令中绑定的内容取出放到if中,同时将ifConditions属性初始化为数组,然后将对象存入其中:{exp,block},其中exp存放了v-if指令块中绑定的内容指向el。由于本例中没有静态节点,此处不分析优化过程。之前关于codegen的文章分析了constcode=generate(ast,options)生成代码的过程。generate会调用genElement解析el,也就是AST语法树。我们看一下genElement的源码:exportfunctiongenElement(el:ASTElement,state:CodegenState):string{if(el.parent){el.pre=el.pre||el.parent.pre}if(el.staticRoot&&!el.staticProcessed){returngenStatic(el,state)}elseif(el.once&&!el.onceProcessed){returngenOnce(el,state)//事实上,我们可以初步知道为什么v-for优先级比v-if高,//因为在解析ast树生成渲染函数代码时,会先解析ast树中v-for相关的属性//然后解析ast树中v-if相关的属性//并且genFor在将el.forProcessed设置为true,防止重复解析v-for相关属性}elseif(el.for&&!el.forProcessed){returngenFor(el,state)}elseif(el.if&&!el.ifProcessed){returngenIf(el,state)}elseif(el.tag==='template'&&!el.slotTarget&&!state.pre){返回genChildren(el,state)||'void0'}elseif(el.tag==='slot'){returngenSlot(el,state)}else{//组件或元素让代码if(el.component){code=genComponent(el.component,el,state)}else{让数据if(!el.plain||(el.pre&&state.maybeComponent(el))){data=genData(el,state)}constchildren=el.inlineTemplate?null:genChildren(el,state,true)code=`_c('${el.tag}'${data?`,${data}`:''//数据}${children?`,${children}`:''//children})`}//模块转换for(leti=0;i
optimize->codegen会先解析AST树中v-for相关的属性,再解析v-if相关的属性。另外,你也可以知道Vue是如何处理v-for和v-if的。