SoFunction
Updated on 2025-04-12

Why vue is more priority than v-if plateau analysis

Preface

Sometimes some interviews are often askedv-forandv-ifWho has the highest priority? Here we will answer this question by analyzing the source code.

The following content is analyzed based on what we are discussing when we talk about v-model, so you can read this article before reading the following content.

Continue to start from compilation

The following examples start with the analysis:

new Vue({
    el:'#app',
    template:`
        <ul>
            <li v-for="(item,index) in items" v-if="index!==0">
                {{item}}
            </li>
        </ul>
    `
})

From the previous article, we can see that there are three steps to compile.

  • parse: parsing template strings to generate AST syntax tree
  • optimize: Optimize the syntax tree, mark static nodes mainly in time, and improve the performance of updating pages
  • codegen: Generate js code, mainly render function and staticRenderFns function

We will follow these three steps again to analyze the above examples.

parse

parseDuring the process, a large number of regular expressions will be used to parse the template. The example at the beginning will be parsed into the followingASTnode:

// Actually, ast has many attributes, I only show the attributes involved in analysis hereast = {
  'type': 1,
  'tag': 'ul',
  'attrsList': [],
  attrsMap: {},
  'children': [{
    'type': 1,
    'tag': 'li',
    'attrsList': [],
    'attrsMap': {
      'v-for': '(item,index) in data',
      'v-if': 'index!==0'
     },
     // attributes parsed by v-if    'if': 'index!==0',
    'ifConditions': [{
      'exp': 'index!==0',
      'block': // Point to el itself    }],
    // V-for parsed properties    'for': 'items',
    'alias': 'item',
    'iterator1': 'index',
    'parent': // Point to its parent node    'children': [
      'type': 2,
      'expression': '_s(item)'
      'text': '{{item}}',
      'tokens': [
        {'@binding':'item'},
      ]
    ]
  }]
}

forv-forInstructions, except for recordingattrsMapandattrsList, there will be new onesfor(corresponding to the object or array to be traversed),aliasiterator1,iterator2correspondv-forThe first, second, and third parameters in the directive binding content. The example at the beginning does not have the third parameter, so there is noiterator2property.

forv-ifInstructions,v-ifThe bound content in the command is taken out and placedifInitialize at the same timeifConditionsThe attribute is an array, and then the object is stored in it:{exp,block},inexpStorev-ifThe content bound in the command,blockPoint toel

optimizeThe process will not be analyzed here, because there are no static nodes in this example.

codegen

Previous article fromconst code = generate(ast, options)Begin to analyze the process of generating code.generateIt will be called internallygenElementUsed to parseel, that isASTSyntax tree. Let's take a lookgenElementSource code:

export function genElement (el: ASTElement, state: CodegenState): string {
  if () {
     =  || 
  }
  if ( &amp;&amp; !) {
    return genStatic(el, state)
  } else if ( &amp;&amp; !) {
    return genOnce(el, state)
  // In fact, from this we can first know why v-for is higher priority than v-if.  // Because when parsing the ast tree to generate render function code, the attributes involved in v-for in the ast tree will be parsed first  // Then parse the properties involved in v-if in the ast tree  // And genFor will set it to true to prevent repeated parsing of v-for related attributes  } else if ( &amp;&amp; !) {
    return genFor(el, state)
  } else if ( &amp;&amp; !) {
    return genIf(el, state)
  } else if ( === 'template' &amp;&amp; ! &amp;&amp; !) {
    return genChildren(el, state) || 'void 0'
  } else if ( === 'slot') {
    return genSlot(el, state)
  } else {
    // component or element
    let code
    if () {
      code = genComponent(, el, state)
    } else {
      let data
      if (! || ( &amp;&amp; (el))) {
        data = genData(el, state)
      }
      const children =  ? null : genChildren(el, state, true)
      code = `_c('${}'${        data ? `,${data}` : '' // data      }${        children ? `,${children}` : '' // children      })`
    }
    // module transforms
    for (let i = 0; i &lt; ; i++) {
      code = [i](el, code)
    }
    return code
  }
}

Next, take a lookgenForandgenIfFunction source code:

export function genFor (el, state , altGen, altHelper) {
  const exp = 
  const alias = 
  const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
  const iterator2 = el.iterator2 ? `,${el.iterator2}` : ''
   = true // avoid recursion
  return `${altHelper || '_l'}((${exp}),` + 
    `function(${alias}${iterator1}${iterator2}){` +
      `return ${(altGen || genElement)(el, state)}` + //Recursively call genElement    '})'
}

In our case, when he handles itliofastWhen the tree is called firstgenElement, processed toforAttributes, at this timeforProcessedIt is a virtual value, and it is called at this timegenFordeal withliThe treev-forRelated attributes. Then callgenElementdeal withliTree, at this timeforProcessedexistgenForhas been marked astrue. thereforegenForWill not be executed, then executedgenIfProcessing andv-ifRelated attributes.

export function genIf (el,state,altGen,altEmpty) {
   = true // avoid recursion
  // Call genIfConditions to process the main properties  return genIfConditions((), state, altGen, altEmpty)
}
function genIfConditions (conditions, state, altGen, altEmpty) {
  if (!) {
    return altEmpty || '_e()' // _e is used to generate empty VNode  }
  const condition = ()
  if () { //That is, the v-if binding value, in the example, it is 'index!==0'    // Generate a js code string with three-item operator    return `(${})?${       genTernaryExp()    }:${      genIfConditions(conditions, state, altGen, altEmpty)    }`
  } else {
    return `${genTernaryExp()}`
  }
  // v-if with v-once should generate code like (a)?_m(0):_m(1)
  function genTernaryExp (el) {
    return altGen
      ? altGen(el, state)
      : 
        ? genOnce(el, state)
        : genElement(el, state)
  }
}

refer toDetailed answers to front-end advanced interview questions

Finally,codegenThe generated js code is as follows:

function render() {
  with(this) {
    return _c('ul', _l((items), function (item, index) {
      return (index !== 0) ? _c('li') : _e()
    }), 0)
  }
}

in:

  • _c: CallcreateElementGo to createVNode
  • _lrenderListFunctions, mainly used to render lists
  • _ecreateEmptyVNodeFunctions are mainly used to create emptyVNode

Summarize

Why is v-for more priority than v-if? In summary, there are three processes for compilation.parse->optimize->codegen. existcodegenDuring the process, the analysis will be performed firstASTand in the treev-forRelated attributes, then parse andv-ifRelated attributes. In addition, you can also knowVuerightv-forandv-ifHow to deal with it.

The above is the detailed content of why v-for is more priority than v-if plateau analysis. For more information about vue priority v-for v-if, please follow my other related articles!