vue中v-if与v-for优先级问题

The局外人 Lv Max

v-if和v-for哪个优先级更高呢?这是面试官常常问到的一个问题,接下来我将针对此类问题进行详细讲解,如有问题欢迎指出~~

vue2

当v-if与v-for一起使用时,vue2中v-for优先级高于v-if

但也面临着一些问题:

当v-if的值不依赖于v-for时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<ul>
<li v-for="item in arr" :key="item.id" v-if="flag">{{ arrs.name }}</li>
</ul>
</template>

<script>
export default {
data() {
return {
flag: false,
arr: [
{ id: 1, name: "刘德华", flag: true },
{ id: 2, name: "张学友", flag: false },
{ id: 2, name: "郭富城", flag: true },
],
};
}
};
</script>

如上述代码,如果flag为false,由于v-for优先级高于v-if,导致输出三个注释节点,显然这是不合理的。
image.png
但,flag这个判断其实如果是false,循环并不需要执行,但是现在跟v-if一起用,不管flag是否是true,一上来都得等循环完了再if判断,完全是浪费。

解决办法是:

1
2
3
4
5
6
7
<template>
<ul>
<template v-if="flag">
<li v-for="item in arr" :key="item.id">{{ item.name }}</li>
</template>
</ul>
</template>

当flag为false, 最终效果可以看出只循环了一次,避免了性能浪费。
image.png
所以将v-if提前,即便v-for优先级高于v-if,也得根据v-if来判断是否进行循环。

当v-if的值依赖于v-for时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<ul>
<li v-for="item in arr" :key="item.id" v-if="item.flag">{{ item.name }}</li>
</ul>
</template>

<script>
export default {
data() {
return {
arr: [
{ id: 1, name: "刘德华", flag: true },
{ id: 2, name: "张学友", flag: false },
{ id: 2, name: "郭富城", flag: true },
],
};
}
};
</script>

代码并没有逻辑上的错误,同样呈现正常效果,没报错
image1.png
每次重新渲染的时候,其实我们只需要item.flag为true的列表的一部分,但渲染时都重新遍历了整个列表,这样做会造成性能浪费。
因为<template>上不能使用key,这种方式就不阐述了,按照上述同样方式进行解决:

1
2
3
4
5
6
7
<template>
<ul>
<template v-if="item.flag">
<li v-for="item in arr" :key="item.id">{{ item.name }}</li>
</template>
</ul>
</template>

这样报错就在正常不过了,因为item未曾定义,所以item.flag报错
image.png
不卖关子了,正确且不造成性能浪费的方式是计算属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<ul>
<li v-for="item in newArr" :key="item.id">{{ item.name }}</li>
</ul>
</template>

<script>
export default {
data() {
return {
flag: false,
arr: [
{ id: 1, name: "刘德华", flag: true },
{ id: 2, name: "张学友", flag: false },
{ id: 2, name: "郭富城", flag: true },
],
};
},
computed: {
newArr() {
return this.arr.filter((item) => item.flag);
},
},
};
</script>

效果一样
image1.png

vue3

当v-if与v-for一起使用时,vue3中v-if优先级高于v-for

都知道vue3在性能优化方面要强于vue2,那么关于v-if与v-for的优先级问题,vue3是怎么做的呢?
看两张图
image4.png
image5.png
图中是vue3代码编译成render函数的结果 有图可以看出当v-if与v-for同级存在时,先执行v-if操作,这也验证了vue3v-if优先级高于v-for。
如图二,我把v-if提前,但编译成的render函数,简直一模一样,未曾变化。这又可以看出vue3底层就是把v-if提前的这个操作,解决了性能浪费问题。所以这就是vue3比vue2性能方面要好的原因。
测试:
.v2.template-explorer
.vue3-template-explorer

当v-if的值不依赖于v-for时:

上述可以看出vue3v-if优先级高于v-for所以不存在性能问题。正常写<li v-for="item in arr" :key="item.id" v-if="flag">即可。

当v-if的值依赖于v-for时:

因为v-if优先级高于v-for的缘故,又会导致被依赖的属性未被定义。这里有两种方式:

第一种方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<ul>
<li v-for="item in newArr" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>

<script setup lang="ts">
import { computed, ref } from "vue";
const arr = ref([
{ id: 1, name: "刘德华", flag: true },
{ id: 2, name: "张学友", flag: false },
{ id: 2, name: "郭富城", flag: true },
]);
const newArr = computed(() => {
return arr.value.filter((v) => v.flag);
});
</script>

计算属性可以解决问题。正常输出,不报错。
image1.png

第二种方式:(不推荐)

1
2
3
4
5
6
7
<template>
<ul>
<template v-for="item in newArr" :key="item.id">
<li v-if="item.flag">{{ item.name }}</li>
</template>
</ul>
</template>

vue3官网明确指出,<template>中可以使用key
image.png
由此得出上述代码,可能对性能浪费没有帮助,但在不考虑性能的情况下,此方法可行。

总结

  • vue2中,v-for的优先级高于v-if
  • vue3中,v-if的优先级高于v-for
  • vue2中,解决v-for优先级高于v-if产生的性能浪费的方式有两种:当v-if不依赖于v-for时,将v-if提前,当v-if依赖于v-for时,使用计算属性
  • vue3中,当v-if不依赖于v-for时,没有性能浪费问题,当v-if依赖于v-for时,使用计算属性解决性能浪费问题。
  • 标题: vue中v-if与v-for优先级问题
  • 作者: The局外人
  • 创建于 : 2024-05-14 11:43:01
  • 更新于 : 2023-09-11 22:01:06
  • 链接: https://dragon-xjy.gitee.io/2024/05/14/vue中v-if与v-for优先级问题/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
 评论