v-for中的key
使用 v-for 更新已渲染的元素列表时,默认使用就地复用策略,列表数据修改的时候,它会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则就地复用之前的元素;我们在使用的时候经常会用到index(即数组的下标)作为key,但其实这时候不推荐的一种使用方法。
举个🌰
const arrList = [
{
id:1,
name:'test1'
},
{
id:2,
name:'test2'
},
{
id:3,
name:'test3'
}
]
<div v-for="(item,index) in arrList" :key="index">{{item.name}}</div>
以上这种是我们做项目时常用到的一种场景,因为不加key,vue会直接报错,所以我这里使用index作为key,下面列举两种常见的数据更新情况。
1.在最后一条数据后再加一条数据
const arrList = [
{
id:1,
name:'test1'
},
{
id:2,
name:'test2'
},
{
id:3,
name:'test3'
},
{
id:4,
name:'我是在最后添加的一条数据'
}
]
此时前三条数据就地复用之前的,新渲染最后一条数据,此时用index作为key,没有问题
2.在中间插入一条数据
const arrList = [
{
id:1,
name:'test1'
},
{
id:4,
name:'我是插队的那条数据'
},
{
id:2,
name:'test2'
},
{
id:3,
name:'test3'
}
]
此时更新渲染数据,通过index定义的key去进行前后数据的对比,如下:
之前的数据 之后的数据
key:0 index:0 name:test1 key:0 index:0 name:test1
key:1 index:1 name:test2 key:1 index:1 name:我是插队的那条数据
key:2 index:2 name:test3 key:2 index:2 name:test2
key:3 index:3 name:test3
通过上面清晰的数据对比,发现除了第一条数据就地复用之前,最后三条数据都进行了重新渲染,明明只插入了一条数据,怎么三条数据都要重新渲染,而我想要的是只有新增的那一条数据重新渲染就可以了。
最好的办法是用数组中不会发生变化的那一项作为key值,对应到项目中,即每一条数据都有一个唯一的id,来标识这条数据的唯一性,使用id作为key值,来看一下向中间插入一条数据,此时会怎样去渲染。
之前的数据 之后的数据
key:1 id:1 index:0 name:test1 key:1 id:1 index:0 name:test1
key:2 id:2 index:1 name:test2 key:4 id:4 index:1 name:我是插队的数据
key:3 id:3 index:2 name:test3 key:2 id:2 in dex:2 name:test2
key:3 id:3 index:3 name:test3
现在对比只有一条数据发生了变化,就是id为4的那条数据,因此只要新渲染这一条数据就可以啦,其他都是就地复用之前的。
因为Virtual DOM 使用Diff算法实现的原因:
下列大致从虚拟Dom的Diff算法实现的角度去解释一下
vue中虚拟DOM的Diff算法,其核心是基于两个假设:
1.两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
2.同一层级的一组节点,它们可以通过唯一的id进行区分
基于以上两点假设,使得虚拟DOM的Diff算法容易很多。
引用React’s diff algorithm中的例子:
当某一层有很多相同的节点时,也就是列表节点时,Diff算法在更新时会默认遵循以上原则,比如一下这个情况:
我们希望在B和c中间加一个F,Diff算法执行起来的时候是这样的:
就是把C更新成F,D更新成C,E更新成D,最后再插入一个E,很明显这样很没有效率。
所以需要使用key来给每一个节点做一个唯一标识,Diff算法就可以正确的识别这个节点,找到正确的位置插入新的节点。
最后总结,key的主要作用就是为了更高效的更新虚拟Dom,另外vue中在使用相同标签名元素的过渡切换时,也会用到key属性,其目的就是为了让vue区分它们,否则vue只会替换其内部属性而不会触发过渡效果。