v-for为什么不能用index做key
# v-for为什么不能用index做key
# 一、key的作用
vue官网描述
key
特殊 attribute 主要用做 Vue 的虚拟 DOM 算法的提示,以在比对新旧节点组时辨识 VNodes。如果不使用 key,Vue 会使用一种算法来最小化元素的移动并且尽可能尝试就地修改/复用相同类型元素。而使用 key 时,它会基于 key 的顺序变化重新排列元素,并且 key 不再存在的元素将始终被移除/销毁。有相同父元素的子元素必须有唯一的 key。重复的 key 会造成渲染错误。
有关虚拟dom和diff算法可以参考我的这篇博客Vue虚拟DOM和Diff算法 (opens new window),里面详细介绍了diff过程中key的作用
其中vue用来判断节点是否相同的方法中,第一步就是对比的key是否相同
function sameVnode (a, b) {
return (
a.key === b.key && // key值
a.tag === b.tag && // 标签名
a.isComment === b.isComment && // 是否为注释节点
// 是否都定义了data,data包含一些具体信息,例如onclick , style
isDef(a.data) === isDef(b.data) &&
sameInputType(a, b) // 当标签是<input>的时候,type必须相同
)
}
2
3
4
5
6
7
8
9
10
如下列表:第二行的F为新插入的元素,当有key的情况下,diff算法只需要一次插入操作即可完成更新过程,
而如果没有key,那么从cf对比开始,要进行三次更新,一次插入操作
很明显,key提高了diff过程的效率
# 二、为什么v-for不建议使用index做key
以下一种常见场景
<div class="list" :style="{background:item.color}" v-for="(item, index) in list" :key="index">
<a-input style="width:200px" :defaultValue="item.color"></a-input>
<a-button @click="del(index)">删除</a-button>
</div>
<script>
list = [{ color: 'red' }, { color: 'blue' }, { color: 'black' }, { color: 'green' }]
del(index) {
this.list.splice(index, 1)
}
</script>
2
3
4
5
6
7
8
9
10
11
12
效果
![](https://gcy-1306312261.cos.ap-chengdu.myqcloud.com/blog/Dec-01-2021 11-12-31.gif)可以看到 明明我们删除的是第一行,可是为什么第一行的输入框一直是red,它一直都没被删掉。
这里有三个重要的点
- 当我们删除第一行,数据发生了变化,数据变化驱动视图层变化,list的长度变为2,那么只剩下了key=0 1 2的节点。
原先存在key=0的节点,vue的复用策略会让继续复用这个节点,所以第一行的节点一直都没被删除。
有时候我们视图上看不出来,是因为我们组件的props和data的数据关联起来了,如这个例子的背景色,看起来是正常的符合删除逻辑的,但是它只是绑定了正确的props,props值改变又触发了一次render过程,导致背景色渲染成了正确的样子。
同理如果是绑定的文本,vue也做了单独处理,直接单纯替换原先的文本节点,所以也会是看起来一切正常的假象
input框因为值没有被双向绑定,只是设定了一个初始值,所以没有触发像background,文本一样的render更新,
所以在我们绑定key值的时候应该尽量使用唯一值,比如后端数据接口返回的id。
我们上面的例子做简单改动
<div class="list" :style="{background:item.color}" v-for="(item, index) in list" :key="index + item.color">
<a-input style="width:200px" :defaultValue="item.color"></a-input>
<a-button @click="del(index)">删除</a-button>
</div>
2
3
4
key绑定成了index + item.color,在这个上下文中成了唯一key
![](https://gcy-1306312261.cos.ap-chengdu.myqcloud.com/blog/Dec-01-2021 11-14-15.gif)
nice