在进入正题之前,我们先思考一下v-for循环为什么要使用key?
key主要用来做DOM diff算法用的。diff算法就是比较两棵树(旧的虚拟 DOM 树和新的虚拟 DOM 树)之间的差异。
v-for循环加key值的必要性
vue中如果没有显式地提供一个 key 属性,Vue 会默认使用列表项的索引作为该项的 key 值。所以给key提供index值和不给其设置key值效果一样。
列表数据修改的时候,他会根据key值去判断某个值是否修改,如果修改,则重新渲染这一项,否则复用之前的元素。
比如我们只想插入一个F,其它都不变,本应该如下图:
而如果按照下图去渲染,各个位置都重新渲染一遍,就有点劳师动众了:
所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。
一句话,key的作用主要是为了高效地更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。
案例说明v-for中key值不能是index
选中第一个节点的复选框,点击删除,vue中是这样操作的,删除后新的数据是吕和王,这时会进行比较,第一个节点的标签一样,值不一样,就会复用原来位置的标签,不会做删除和创建,直接将吕覆盖张,第一个节点就显示吕了,但是并没有删除,所以第一个节点还是被选中的。
示例中没有给key值,默认用了index做为key值。看下图为操作后的效果:
<template> <div> <ul> <liv-for="(item, index) in lists"> <input type="checkbox" :value="item.text" /> {{ item.text }} </li> </ul> <button @click="remove">删除</button> </div> </template> <script> export default { data() { return { lists: [ { id: 1, text: '张' }, { id: 2, text: '吕' }, { id: 3, text: '王' } ] }; }, methods: { remove() { //注意这里是shift this.lists.shift(); } } }; </script>
我们在选中最后一个节点的复选框(王的复选框),点击删除,这时候删除完会发现没有被选中的了。我们点击删除时,删除的是第一个数据,但dom中其实是删除的最后一个节点。因为在最后一个节点中的复选框是选中的,删除后,选中复选框没有被选中,说明被删除了。
再分析:
当我们选择了最后一个多选框,删除第一个节点操作后,两个虚拟树进行比较,index为0和1由于还在,所以两个树之间的数据只是简单地移动。而index为2的节点(也就是最后一个节点)在新虚拟树上没有,于是直接删除。
使用数据中index做为key
<ul> <li v-for="(item, index) in lists" :key="index"> <input type="checkbox" :value="item.text" /> {{ item.text }} </li> </ul>
情况跟未加key的情况一样。分析与上面同。
使用数据中id做为key
<ul> <li v-for="(item, index) in lists" :key="item.id"> <input type="checkbox" :value="item.text"/> {{item.text}} </li> </ul>
则不会出现上面的情况,这就减少了渲染错误。