列表渲染中的key

在Vue的列表渲染中,绑定组件的key属性来唯一的标识渲染列表的元素

在学到Vue的Key的作用时候,不是特别清楚它的具体功能和作用,查找了几篇博客和视频后,有一点自己的理解

没有Key的渲染

在Vue3的文档中有一段话

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

结合这段话,我们来看下面的例子,可以点击尝试

image-20220120144702109

首先我们将每个元素的输入框区分一下,点击第二个delete也就是删除第二个元素

image-20220120144924064

可以发现结果并不是预期的,为什么前面的文本变成第三个元素的文本但是随后的表单却没有变呢?

结合上面提到的文档中的内容

它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素

个人认为这个列表的每一项可以分为两部分,一部分是前面的文本叫做p,后一部分表单为f,如第二个元素

1
2
3
4
No.2: {
p:{"id": 2, "value": 2}
f:input:text
}

当删除第二个元素时,因为此时Vue不知道如何来唯一的确定每个元素,所以只能从头开始遍历一个个替换,新列表和旧列表的信息如下所示

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
26
27
28
{
OldList:
{
No.1: {
p:{"id": 1, "value": 1}
f:input: text
}
No.2: {
p:{"id": 2, "value": 2}
f:input: text
}
No.3: {
p:{"id": 3, "value": 3}
f:input: text
}
}
NewList:
{
No.1: {
p:{"id": 1, "value": 1}
f:input: text
}
No.3: {
p:{"id": 3, "value": 3}
f:input: text
}
}
}

遍历替换的过程是新的列表会依次和旧的列表比较,首先比较第一个元素,发现第一个元素的p和f都一样,所以不进行更新。到第二个元素时,发现p不一样但是f都一样,所以只替换p。到第三个元素时发现新列表已经遍历结束了,所以就删除旧列表第三个元素

因为对于Vue来说有一个就地更新的机制,并且判断每个input标签是否一样是不会比较他们的value属性,所以就产生了这种局部更新的bug

当我们改变一下代码,将第三个元素的表单input标签的类型改成radio

image-20220120151612397

再进行删除第二个元素

image-20220120151642201

发现此时删除后的结果就符合预期了,因为改变了第三个元素的type,导致第二个和第三个元素的f不同,所以Vue就会进行更新

使用key的渲染

在上面代码中加入key的定义v-for="item,i in array" :key="item.id",再次尝试删除

image-20220120152015906

可以发现结果符合我们的预期,这是因为使用key后,Vue知道了如何分辨每个item,通过比较key的不同就可以确定要更新的不仅仅是前面的p,整个p和f都需要更新