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

  • 优先级比较: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()
    
    });
    优先级比较:v-for 和 v-if哪个更高?
    微信扫码分享

    0

    0

    分享
  • 会员

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

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

    还没有评论,赶紧来抢沙发吧!

    培根过期一个月了还能吃吗 培根过期一天还能吃吗

    培根是很常见的一种肉质食品,它的味道好,营养丰富,深受人们的喜欢,很多人都会吃培根。那么培根过期一个月了还能吃吗? 培根 …

    春笋需要焯水吗(春笋需要焯水吗怎么焯)

    春笋是现代人家里很常见的一种家常菜,经常可以看到有人家里吃春笋,春笋有很高的营养价值,那么春笋需要焯水吗? 春笋需要焯水 …

    别不信!当对方让你产生以下感觉时,就是上天在提醒你远离

    有这样一句话,道出了爱情中的微妙情感:“我眼中只有你,而你的世界却未曾有我。” 这也许就是爱的无奈,我们期待着所爱之人能 …

    赞美蓝天白云草地 形容蓝天白云草地词语?

    形容蓝天白云草地词语? 1、天空一碧如洗,灿烂的阳光正从密密的松针的缝隙间射下来,形成一束束粗粗细细的光柱,把飘荡着轻纱 …

    阿里山位于哪个省

    阿里山在我国的台湾省,海拔高度为2216米,由十八座高山组成,每年都会有很多游客前去游玩,不管是日出、云海、晚霞,都是非 …

    无糖食品真的无糖吗 阿尔发无糖食品真的无糖吗

    一些减肥人士或有特殊疾病的人,饮食中需要控制糖的摄入,对此很多商家都推出了无糖食品,那么无糖食品真的无糖吗? 无糖食品真 …

    发烧了喝感冒清热颗粒有用吗(感冒退热颗粒不发烧可以喝吗)

    普通感冒或者流行性感冒引起的发热,都可以服用感冒退热颗粒,具有退热效果。 一般普通感冒或者流行感冒,大多数属于病毒性感染 …

    识人术:人际交往简单实用的读心术,助你读懂人心,很准!

    老祖宗曾说,知人不必言尽,言尽则无友;识人不必探尽,探尽则多怨。与人相处,是一门学问。因为人心隔肚皮,眼睛只能识人面,最 …

    玻璃刮怎么用

    使用玻璃刮时,要在玻璃上均匀的喷洒清洁剂,等待两分钟后,用玻璃刮从上至下将清洁剂刮除,最后用毛巾将玻璃刮上的清洁剂擦拭干 …

    蔬菜沙拉不仅营养丰富,还可以瘦身美颜

    蔬菜沙拉是一种很营养健康的吃法,因为这种吃法可以保留住食物中的营养成分,它是利用3种或3种以上蔬菜制作而成的食物,做法简 …

    血氧偏低有什么影响(血氧低于的危害有哪些)

    血氧是指血氧饱和度,血氧饱和度低于95%,短时间轻微偏低一般没有明显危害,如果长时间偏低或偏低严重,一般有心率增快、消化 …

    2022芒种养生的食疗食谱

    2022芒种养生的食疗食谱有哪些你知道吗?人生如同芒种,同样需要,种人品,种能力,种素养,种修为……到了收获时节,才能收 …

    桔梗的营养价值及药用价值

    桔梗是中医中常见的一味中草药,对于很多疾病的治疗都有着很好的帮助,有的地区将它作为腌制品的辅助佐料。 桔梗的营养价值 1 …

    热水袋排气孔怎么打开

    在温热状态下,用手用力挤压排气孔两侧,在微微翘起的一边用指甲盖即可叩开。打开后要小心里边液体流出来,用手稍微提着点排气孔 …

    老年人适合运动

    1.散散步。对于身体状况不好的老人,剧烈运动可能是做不到的,那就去散步吧。这是最简单的。在马路上、公园里随便走走,走前走 …

    羊毛衫机洗缩水怎么办

    羊毛衫机洗缩水后,可以使用白醋浸泡、高温蒸煮、熨烫处理使其恢复。将缩水的羊毛衫浸泡在混有白醋的清水中,使羊毛衫软化,或者 …

    吃了芒果嘴巴痒怎么办 吃了芒果嘴巴痒怎么办擦药吗?

    芒果果肉软滑可口,营养成分丰富,受到不少人的喜欢,但是有的人吃了芒果后,嘴巴会有点发痒,那么吃了芒果嘴巴痒怎么办呢? 吃 …

    吃姑娘果对身体好吗(吃姑娘果的好处)

    姑娘果是生活中常见的一种水果,其中的营养价值以及食用价值比较高,那么吃姑娘果对身体好吗?吃姑娘果的好处和坏处? 吃姑娘果 …

    怎么吃水果最健康(水果怎么吃最好)

    水果美味,但是很多年老、或体弱的人阳气不足,一吃凉食会出现腹泻。这让许多人对水果望而生畏。所以,大家不妨试试热吃水果!比 …

    胡萝卜汁生喝还是熟喝有营养

    蔬菜汁是很多人都喜欢喝的一种饮品,其中以胡萝卜汁色泽最为鲜美,营养价值也最高。那么胡萝卜汁生喝还是熟喝,胡萝卜和什么榨汁 …