美食 健康 常识 生活 日常 家居 养生 心理学 国学 中医 植物 营销 动物 汽车 管理 旅游 投资 人工智能 数字化 消费 元宇宙 金融 饮食 史学 经济 医药
  • 会员

  • 优先级比较:v-for 和 v-if哪个更高?

    结论

    1、本身并不建议将v-for和v-if同时使用的。

    2、vue2里面v-for比v-if的优先级更高。因为vue2在模板编译的时候会先处理v-for再处理v-if,所以生成的渲染函数会先执行循环,然后在循环里面再执行条件判断。

    3、这样做带来的问题就是

    对于场景1:<li v-for="user in users" v-if="user.show">

    每次重新渲染的时候,都要重新遍历整个列表,其实我们只需要列表的一部分,这样做浪费性能。推荐的做法是,通过计算属性先过滤出我们需要的部分,再去渲染,更高效。

    对于场景2: <li v-for="user in users" v-if="globalShow">

    globalShow这个判断其实如果是false,循环并不需要执行,但是现在跟v-if一起用,不管globalShow是否是true都要执行循环,完全是浪费。推荐的做法是将v-if上移到ul容器。

    4、需要注意的是,vue3的breaking change,在vue3中v-if的优先级比v-for高,所以如果同时使用的话,对于场景1,这个时候user还没有,v-if="user.show"就会报错

    5、一般我们如果有用eslint,也会给我们报错,对应的规则是:vue/no-use-v-if-with-v-for

    实际例子

    例如:以下的模板,将会生成下面的渲染函数

    <ul>
    
        <li v-for="user in users" v-if="user.isActive" :key="user.id">
    
            {{ user.name }}
    
        </li>
    
    </ul>

    生成的渲染函数如下

    with(this) {
    
        return _c('ul', _l((users), function (user) {
    
            return (user.isActive) ? _c('li', user.name) : _e()
    
        }), 0)
    
    }

    从上面生成的渲染函数可以看出,会先执行_l遍历user,在里面进行条件判断

    源码

    处理v-if和v-for的源码

    src/compiler/index.js

    // 模板解析,生成ast树
    
    const ast = parse(template.trim(), options)
    
    if (options.optimize !== false) {
    
        optimize(ast, options)
    
    }
    
    const code = generate(ast, options)

    根据ast生成代码,假如是上面的模板,生成的ast简化后如下

    // 可以看出v-for和v-if都解析出来了
    
     ast = {
    
         'type': 1,
    
         'tag': 'ul',
    
         'attrsList': [],
    
         'attrsMap': {},
    
         'children': [{
    
         'type': 1,
    
         'tag': 'li',
    
         'attrsList': [],
    
         'attrsMap': {
    
             'v-for': 'user in users',
    
             'v-if': 'user.show'
    
         },
    
         // v-if解析出来的属性
    
         'if': 'user.show',
    
         'ifConditions': [{
    
             'exp': 'user.show',
    
             'block': // 指向el自身
    
         }],
    
         // v-for解析出来的属性
    
         'for': 'users',
    
         'alias': 'user',
    
         'iterator1': 'index',
    
         'parent': // 指向其父节点
    
         'children': [
    
             'type': 2,
    
             'expression': '_s(user)'
    
             'text': '{{user}}',
    
             'tokens': [
    
                 {'@binding':'user'},
    
             ]
    
          ]
    
         }]
    
     }

    compiler/codegen/index.js

    // generate 调用 genElement
    
    const code = ast ? genElement(ast, state) : '_c("div")'
    
    // genElement里面的处理
    
    if (el.staticRoot && !el.staticProcessed) {
    
    return genStatic(el, state)
    
    } else if (el.once && !el.onceProcessed) {
    
    return genOnce(el, state)
    
    // 从这可以看出来,先执行genFor,处理v-for指令,在genFor里面会递归调用genElement,继续处理v-if,genFor会将forProcessed设为true,这样下次进来的时候就不会处理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 {
    
    // 最后这里处理标签等
    
    const children = el.inlineTemplate ? null : genChildren(el, state, true)
    
    code = `_c('${el.tag}'${
    
    data ? `,${data}` : '' // data
    
    }${
    
    children ? `,${children}` : '' // children
    
    })`
    
    }
    
     
    
    // genFor的代码
    
    const exp = el.for // 对应上面ast的 for: users
    
    const alias = el.alias // alias: user
    
    // iterator1 对应v-for的(item,key,index) in items的key
    
    // iterator2 对应的是index
    
    // 通常我们遍历数组 key就是index
    
    // 假如我们遍历的是对象 key就是对象的key,index就是遍历的索引
    
    const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
    
    const iterator2 = el.iterator2 ? `,${el.iterator2}` : ''
    
    el.forProcessed = true // 下次递归调用genElement的时候就不会重复处理v-for了
    
    return `${altHelper || '_l'}((${exp}),` +
    
    `function(${alias}${iterator1}${iterator2}){`
    
     
    
    // 这里处理完了v-for,递归调用genElement继续处理v-if
    
    `return ${(altGen || genElement)(el, state)}` +
    
    '})'
    
    最终会生成类似如下的代码返回出去
    
    
    
    
    
    _l((users), function(user, index) {
    
        // 如果有v-if 前面就会有个条件判断,如user.isActive
    
        return (user.isActive) ? _c('li', user.name) : _e()
    
    });
  • 会员

  • 上一篇: RUBY编程语言中文介绍PDF版

    下一篇: php字符串怎么只保留字母

    发表回复

    红薯和牛奶可以一起吃吗(红薯和牛奶可以一起吃吗?)

    网传红薯不能和高蛋白质的食物一起吃,那牛奶也属于高蛋白质的食物之一,不知道红薯和牛奶能不能一起吃呢?网上说的饮食禁忌是真 …

    天津美食大搜罗 天津美食合集

      娜娜家nana’s cheese jar   推荐理由:坐落在大悦城骑鹅公社里,在直梯一上来就看见。在这 …

    樱桃千禧果的功效 樱桃千禧果的功效与作用

    樱桃千禧果也就是平时吃的圣女果,两者的营养成分差不多,只不过樱桃千禧果在普通圣女果的基础上其口感更佳,糖度更高,更适合当 …

    打卡京郊这4个溶洞

    PART.01 石花洞 石花洞又名潜真洞、十佛洞(石佛洞),以天然形成的石花而闻名。如果将石花洞喻为一幅精美的画卷,从大 …

    香瓜子的功效与作用 香瓜子的功效与作用及营养价值

    香瓜子是聚合闲谈时必不可少的零食,那经常吃香瓜子对身体有什么好处呢?吃香瓜子又有没有什么需要注意的事项吗? 润肠通便 香 …

    2023年浙江几月份是梅雨季节 浙江梅雨季节有几个月

    2023年浙江几月份是梅雨季节 浙江梅雨年际差异很大,平均入梅日为6月9日,出梅日为7月11日,集中期为30天。从初步统 …

    炒茼蒿怎么弄(如何炒苘蒿)

    1、食材:茼蒿500克,盐15克。 2、首先,将茼蒿洗净,然后切成一段段的。 3、之后,再将葱洗干净,切成葱花。 4、开 …

    宝宝山药瘦肉粥的做法 山药肉粥怎么做给宝宝吃

    山药瘦肉粥吃起来很滑腻,而且味道还很不错,那么宝宝山药瘦肉粥的做法是什么?山药瘦肉粥一岁宝宝能吃吗? 宝宝山药瘦肉粥的做 …

    干荔枝的功效与作用及食用方法(荔枝干的用处)

    鲜荔枝汁多,肉鲜美,很受欢迎,但还是有人把荔枝做成荔枝干吃。这种荔枝干有什么作用吗?怎么吃荔枝干? 荔枝收获季节很短,容 …

    土制红糖的方法 机制红糖和土制红糖

    1、先用电动榨汁机把一根根甘蔗挤榨出甜汁,榨好的汁先放在池子里备好。 2、然后把甘蔗汁放进土炉灶上的大土锅里面蒸煮、熬制 …

    柠檬雪梨冻的做法(柠檬冰糖雪梨怎么做法)

    1、食材:雪梨1个,腌制过的柠檬1个,土红糖适量。 2、把全部食材准备好。 3、雪梨去皮,然后把中间的果心挖出来干净。 …

    美食知识大全最新

    人的一生离不开吃,但是要确保能够吃的安全,吃饭健康,吃的养生这是一门学问。今天州姐就跟大家要聊聊关于吃啦! 1.吃红薯叶 …

    水煮牛肉加宽粉的做法(牛肉炖宽粉的做法大全)

    1、用料:水煮牛肉一份,宽粉适量。 2、锅中加入500ml的清水。 3、水开后加入自带的牛油底料。 4、放入自备宽粉。 …

    微波炉加热汤圆要几分钟才能熟 什么人不适合吃汤圆

    汤圆是用糯米粉制作的一种传统美食,它的口味比较丰富,有豆沙味、花生味、紫薯味以及水果味等,很多人都喜欢吃汤圆。汤圆可以用 …

    姜茶怎么弄 吃完螃蟹喝姜茶,姜茶怎么弄

    1、将生姜清洗干净。 2、将生姜切片,由于是用来煮茶的,所以可稍微切厚一点。 3、将姜片放进锅中同时倒入适量清水。 4、 …

    小孩能吃蛤蜊吗 蛤蜊小孩能不能吃

    一般情况下,小孩可以适量吃一些蛤蜊,不会对身体造成不良的影响。蛤蜊的营养价值高,宝宝适量食用是有一定好处的。下面让我们具 …

    羊绒围巾掉毛粘衣服怎么办

    羊绒围巾掉毛粘衣服,可以对其进行清洗,准备一盆三十度的温水,向其中加入中性洗发水或者淀粉,混合均匀后,将羊绒围巾浸泡在其 …

    虾条的做法宝宝 虾条的家常做法

    1、食材:虾2只、鸡蛋1个、玉米淀粉10g。 2、蛋黄蛋白分离,蛋白放冰箱冷冻。 3、虾洗净去虾线剁成泥。蛋黄、虾泥和虾 …

    双面羊绒大衣怎么清洗

    双面羊绒大衣可以直接水洗,将衣服浸泡在有洗涤剂的温水中,浸泡十五分钟后,用手挤压、拍揉,就能将污渍清除,最后用清水漂洗干 …

    冬瓜猪肉馅饺子的做法 冬瓜猪肉馅饺子怎么做

    1、原料:猪肉馅、冬瓜、面粉、盐、香油、蚝油、十三香、葱头、姜、生抽各适量。 2、先和面,面里可以加入一点点盐,这样可以 …