Home > Article > Web Front-end > Vue priority comparison: why v-for is higher than v-if
vue Why does v-for have a higher priority than v-if? The following article will answer this question by analyzing the source code. I hope it will be helpful to everyone!
Sometimes in some interviews, we often ask who has higher priority, v-for
or v-if
, here Let’s answer this question by analyzing the source code.
The following content is analyzed on the basis of When we talk about v-model, what are we talking about?, so you can read this article before reading the following content.
Let’s start with the following example:
new Vue({ el:'#app', template:` <ul> <li v-for="(item,index) in items" v-if="index!==0"> {{item}} </li> </ul> ` })
As you can see from the previous article, there are three steps to compilation
Let’s analyze the above example by following these three steps again.
parseIn the process, a large number of regular expressions will be used to parse the template. The opening example will be parsed into the following AST
nodes:
// 其实ast有很多属性,我这里只展示涉及到分析的属性 ast = { 'type': 1, 'tag': 'ul', 'attrsList': [], attrsMap: {}, 'children': [{ 'type': 1, 'tag': 'li', 'attrsList': [], 'attrsMap': { 'v-for': '(item,index) in data', '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'}, ] ] }] }
for the v-for
directive, in addition to records in attrsMap
and attrsList
, will also add for
(corresponding to the object or array to be traversed), alias
, iterator1
, iterator2
corresponding The first, second, and third parameters in the v-for
instruction binding content. The example at the beginning does not have the third parameter, so there is no iterator2
attribute.
For the v-if
instruction, take out the content bound in the v-if
instruction and put it in if
, and initialize it at the same time ifConditions
The attribute is an array, and then the object is stored in it: {exp,block}
, where exp
stores the binding in the v-if
instruction The specified content, block
points to el
.
optimize The process is not analyzed here because there are no static nodes in this example.
The previous article analyzed the process of generating code starting from const code = generate(ast, options)
,generate
internally calls genElement
to parse el
, which is the AST
syntax tree. Let’s take a look at the source code of genElement
:
export function genElement (el: ASTElement, state: CodegenState): string { if (el.parent) { el.pre = el.pre || el.parent.pre } if (el.staticRoot && !el.staticProcessed) { return genStatic(el, state) } else if (el.once && !el.onceProcessed) { return genOnce(el, state) // 其实从此处可以初步知道为什么v-for优先级比v-if高, // 因为解析ast树生成渲染函数代码时,会先解析ast树中涉及到v-for的属性 // 然后再解析ast树中涉及到v-if的属性 // 而且genFor在会把el.forProcessed置为true,防止重复解析v-for相关属性 } else if (el.for && !el.forProcessed) { return genFor(el, state) } else if (el.if && !el.ifProcessed) { return genIf(el, state) } else if (el.tag === 'template' && !el.slotTarget && !state.pre) { return genChildren(el, state) || 'void 0' } else if (el.tag === 'slot') { return genSlot(el, state) } else { // component or element let code if (el.component) { code = genComponent(el.component, el, state) } else { let data if (!el.plain || (el.pre && state.maybeComponent(el))) { data = genData(el, state) } const children = el.inlineTemplate ? null : genChildren(el, state, true) code = `_c('${el.tag}'${ data ? `,${data}` : '' // data }${ children ? `,${children}` : '' // children })` } // module transforms for (let i = 0; i < state.transforms.length; i++) { code = state.transforms[i](el, code) } return code } }
Next, let’s take a look at the function source code of genFor
and genIf
:
export function genFor (el, state , altGen, altHelper) { const exp = el.for const alias = el.alias const iterator1 = el.iterator1 ? `,${el.iterator1}` : '' const iterator2 = el.iterator2 ? `,${el.iterator2}` : '' el.forProcessed = true // avoid recursion return `${altHelper || '_l'}((${exp}),` + `function(${alias}${iterator1}${iterator2}){` + `return ${(altGen || genElement)(el, state)}` + //递归调用genElement '})' }
In our example, when he processes the ast
tree of li
, he will first call genElement
and process the for
attribute At this time, forProcessed
is a virtual value. At this time, genFor
is called to process the v-for
related attributes in the li
tree. Then call genElement
to process the li
tree, because forProcessed
has been marked as true
in genFor
. Therefore genFor
will not be executed, and then genIf
will be executed to process the attributes related to v-if
.
export function genIf (el,state,altGen,altEmpty) { el.ifProcessed = true // avoid recursion // 调用genIfConditions主要处理el.ifConditions属性 return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty) } function genIfConditions (conditions, state, altGen, altEmpty) { if (!conditions.length) { return altEmpty || '_e()' // _e用于生成空VNode } const condition = conditions.shift() if (condition.exp) { //condition.exp即v-if绑定值,例子中则为'index!==0' // 生成一段带三目运算符的js代码字符串 return `(${condition.exp})?${ genTernaryExp(condition.block) }:${ genIfConditions(conditions, state, altGen, altEmpty) }` } else { return `${genTernaryExp(condition.block)}` } // v-if with v-once should generate code like (a)?_m(0):_m(1) function genTernaryExp (el) { return altGen ? altGen(el, state) : el.once ? genOnce(el, state) : genElement(el, state) } }
ReferenceDetailed answers to front-end advanced interview questions
Finally, the js code generated by codegen is as follows:
function render() { with(this) { return _c('ul', _l((items), function (item, index) { return (index !== 0) ? _c('li') : _e() }), 0) } }
Among them:
_c
: Call createElement
to create VNode
_l
: renderList
function, mainly used to render the list
_e
: createEmptyVNode
Function, mainly used to create empty VNode
Why does v-for have a higher priority than v-if? In summary, there are three processes in compilation, parse
->optimize
->codegen
. In the codegen
process, the attributes related to v-for
in the AST
tree will first be parsed, and then v-if
will be parsed. related properties. In addition, you can also know how Vue
handles v-for
and v-if
.
(Learning video sharing: vuejs introductory tutorial, Basic programming video)
The above is the detailed content of Vue priority comparison: why v-for is higher than v-if. For more information, please follow other related articles on the PHP Chinese website!