Home  >  Article  >  Web Front-end  >  Vue priority comparison: why v-for is higher than v-if

Vue priority comparison: why v-for is higher than v-if

青灯夜游
青灯夜游forward
2023-03-14 19:44:191648browse

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!

Vue priority comparison: why v-for is higher than v-if

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.

Continue to start with compilation

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

  • parse: Parse the template string to generate an AST syntax tree
  • optimize: Optimize the syntax tree, mainly marking static nodes to improve the efficiency of updating the page Performance [Related recommendations: vuejs video tutorial, web front-end development]
  • codegen: Generate js code, mainly render function and staticRenderFns function

Let’s analyze the above example by following these three steps again.

parse

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 = {
  &#39;type&#39;: 1,
  &#39;tag&#39;: &#39;ul&#39;,
  &#39;attrsList&#39;: [],
  attrsMap: {},
  &#39;children&#39;: [{
    &#39;type&#39;: 1,
    &#39;tag&#39;: &#39;li&#39;,
    &#39;attrsList&#39;: [],
    &#39;attrsMap&#39;: {
      &#39;v-for&#39;: &#39;(item,index) in data&#39;,
      &#39;v-if&#39;: &#39;index!==0&#39;
     },
     // v-if解析出来的属性
    &#39;if&#39;: &#39;index!==0&#39;,
    &#39;ifConditions&#39;: [{
      &#39;exp&#39;: &#39;index!==0&#39;,
      &#39;block&#39;: // 指向el自身
    }],
    // v-for解析出来的属性
    &#39;for&#39;: &#39;items&#39;,
    &#39;alias&#39;: &#39;item&#39;,
    &#39;iterator1&#39;: &#39;index&#39;,

    &#39;parent&#39;: // 指向其父节点
    &#39;children&#39;: [
      &#39;type&#39;: 2,
      &#39;expression&#39;: &#39;_s(item)&#39;
      &#39;text&#39;: &#39;{{item}}&#39;,
      &#39;tokens&#39;: [
        {&#39;@binding&#39;:&#39;item&#39;},
      ]
    ]
  }]
}

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 ifConditionsThe 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.

codegen

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 === &#39;template&#39; && !el.slotTarget && !state.pre) {
    return genChildren(el, state) || &#39;void 0&#39;
  } else if (el.tag === &#39;slot&#39;) {
    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(&#39;${el.tag}&#39;${        data ? `,${data}` : &#39;&#39; // data      }${        children ? `,${children}` : &#39;&#39; // 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}` : &#39;&#39;
  const iterator2 = el.iterator2 ? `,${el.iterator2}` : &#39;&#39;

  el.forProcessed = true // avoid recursion
  return `${altHelper || &#39;_l&#39;}((${exp}),` + 
    `function(${alias}${iterator1}${iterator2}){` +
      `return ${(altGen || genElement)(el, state)}` + //递归调用genElement
    &#39;})&#39;
}

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 || &#39;_e()&#39; // _e用于生成空VNode
  }

  const condition = conditions.shift()
  if (condition.exp) { //condition.exp即v-if绑定值,例子中则为&#39;index!==0&#39;
    // 生成一段带三目运算符的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(&#39;ul&#39;, _l((items), function (item, index) {
      return (index !== 0) ? _c(&#39;li&#39;) : _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

Summary

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!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete