v-for
是vue中最常用的指令,也是面试题中问到最多的,这里干脆都整理一下。
正文
本篇并不算太麻烦,只是简单的整理一下即可。
v-for与v-if优先级
因为现在有vue3了,所以这里回答会和vue使用版本的不同有关。
在vue2中,v-for的优先级高于v-if
在vue3中,v-if的优先级高于v-for
vue2
当它们处于同一节点,v-for
的优先级比 v-if
更高,这意味着 v-if
将分别重复运行于每个 v-for
循环中。当你只想为部分项渲染节点时,这种优先级的机制会十分有用,如下:
1 | <li v-for="todo in todos" v-if="!todo.isComplete"> |
上面的代码将只渲染未完成的 todo。
而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if
置于外层元素 (或 [`) 上。如:
1 | <ul v-if="todos.length"> |
vue3
当它们同时存在于一个节点上时,v-if
比 v-for
的优先级更高。
这意味着 v-if
的条件将无法访问到 v-for
作用域内定义的变量别名:
1 | <!-- |
在外先包装一层 <template>
再在其上使用 v-for
可以解决这个问题 (这也更加明显易读)
1 | <template v-for="todo in todos"> |
v-for与v-if不推荐混用
当面试官问到你为什么v-for与v-if不推荐混用的时候,按照下边的说法去回答就可以。
节省性能,v-for与v-if混用,会导致每次渲染的时候都要进行条件判断,进而影响页面渲染的性能。
当 Vue 处理指令时,v-for
比 v-if
具有更高的优先级,如果把 v-for
和 v-if
写在同一元素上,举例。
1 | <ul> |
将会经过如下运算:
1 | this.users.map(function (user) { |
假设 users 数组有 10000 项,但只有一个 user 是 isActive,也会遍历整个 users 数组。
这样对性能是极不友好的。
通过将其更换为在如下的一个计算属性上遍历:
1 | <ul> |
我们将会获得如下好处:
- 过滤后的列表只会在
users
数组发生相关变化时才被重新运算,过滤更高效。 - 使用
v-for="user in activeUsers"
之后,我们在渲染的时候只遍历活跃用户,渲染更高效。 - 解耦渲染层的逻辑,可维护性 (对逻辑的更改和扩展) 更强。
为了获得同样的好处,我们也可以把:
1 | <ul> |
更新为:
1 | <ul v-if="shouldShowUsers"> |
通过将 v-if
移动到容器元素,我们不会再对列表中的每个用户检查 shouldShowUsers
。
取而代之的是,我们只检查它一次,且不会在 shouldShowUsers
为否的时候运算 v-for
。
v-for为什么要有key
这里,我们首先附上官方的说法。
key
这个特殊的 attribute 主要作为 Vue 的虚拟 DOM 算法提示,在比较新旧节点列表时用于识别 vnode。在没有 key 的情况下,Vue 将使用一种最小化元素移动的算法,并尽可能地就地更新/复用相同类型的元素。
如果传了 key,则将根据 key 的变化顺序来重新排列元素,并且将始终移除/销毁 key 已经不存在的元素。
同一个父元素下的子元素必须具有唯一的 key,重复的 key 将会导致渲染异常。
按照这套说法,key是唯一标识,如果你操作数组中的元素,没有key来进行唯一标识,就会出现渲染混乱的情况。
key 在这里是一个通过 v-bind 绑定的特殊 attribute。请不要和在 v-for 中使用对象里所提到的对象属性名相混淆。
以前有人反驳我,说即便是不用key,v-for还是会正常渲染,只是代码提示报错。
这里,我们附上一个小例子来反驳这类说法。
1 | <template> |
- vue中列表循环需要加
:key='唯一标识'
,唯一标识尽量是id,目的是为了高效地更新虚拟DOM - key主要用于dom diff算法,diff算法为同级比较,比较当前标签上的key还有他当前的标签名,如果key和标签名都一样时只移动,不会重新创建元素和删除元素
- 没有key地时候默认使用就地复用策略。如果数据的顺序被改变,vue不是移动DOM元素来匹配数据项的改变,而是简单复用原来位置的每个元素,在进行比较时发现标签一样值不一样时,就会复用之前的位置,将新值直接放到该位置,以此类推,最后多出一个就会把最后一个删除掉。
v-for不推荐index作为key
尽量不要使用索引值index作key值,一定要用唯一标识的值,如id等。
这在很多前端开发人员眼中是常识,但很少有人深究,若是细究不用index作为key的原因,其实很简单。
数组中,index
作为数组中元素的唯一标识,在没有数据改变的情况下,用来当做v-for
渲染的key其实是没有问题。
若是数据有所改变,此时仍用索引index为key,当向数组中指定位置插入一个新元素后,因为这时候会重新更新index索引,对应着后面的虚拟DOM的key值全部更新了,这个时候还是会做不必要的更新,就像没有加key一样,因此index虽然能够解决key不冲突的问题,但是并不能解决复用的情况。
结语
v-for这篇本质上其实牵涉到了diff算法等vue渲染的底层原理,但本篇内容长度,就不深入细说。
后续会专门就渲染和diff算法专门出一篇文档。
参考
详解v-for中:key属性的作用 - 掘金 (juejin.cn)