v-if和v-for优先级问题

749 阅读1分钟

1.问题: v-if和v-for同时使用,那个优先级更高

2.分析

<template>
 <p v-for="child in children" v-if="isFolder">{{child.title}}</p>
</template>
  const app = new Vue({... })
  console.log(app.$options.render); 

从打印输出可以看出,_l 循环遍历的for ,里面再执行(isFolder)? 条件判断。

(function anonymous( 
) { 
with(this){return _c('div',{attrs:{"id":"demo"}},[_c('h1',[_v("xxx")]),_v(" "), 
_l((children),function(child){return (isFolder)?_c('p', 
[_v(_s(child.title))]):_e()})],2)} 
}) 

vue会先将template模板 编译成AST抽象语法树。 从源码compiler/codegen/index.js 分析。 在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)
  } else if (el.for && !el.forProcessed) { //1.for命令优先执行
    return genFor(el, state)
  } else if (el.if && !el.ifProcessed) {//2.这里才执行if
    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 {
...}

3.结论:

  1. 在源码中分析我们得出,vue把模板编译成AST抽象语法树时,genElement方法是先执行genFor方法,再执行genIf。所以for优先。
  2. 由于for先执行,无论如何判断,循环都会执行,浪费了性能。

4.优化方案:

  • 把if提取到for的外部,优先判断。
  • 如果出现在条件内部,可以提前把整个list 先过滤一遍,再交给template循环。(可以使用计算属性优化下次访问数组的效率)