vue3 不推荐使用index作为v-for遍历的key

结论: 

  1. 使用index 作为key时, 当逆序添加或者逆序删除的时候会破坏数据结构,从而产生没必要的dom更新,导致效率低。
  2. 用index作为key时,如果结构中包含输入类的dom时,会产生错误的dom更新。
  3. 使用index和其他值拼接作为key时,和使用index作为key类似,每次的key都是不一样的,所以没办法做到增加效率。
  4. 再开发中推荐使用集合中固定的唯一标识作为key,例如唯一的id或者codeNumber等。
  5. 当不存在unshift的添加或者shift删除的时候可以使用index作为key,不会有什么影响,但是不推荐,万一养成习惯就不好改正了。

下面讲针对结论1和2进行简单的讲述(前提: 需要已经掌握了vue3的diff算法, 本文中没有对diff算法做解释,所以之前没有看过或者了解过diff算法的可能不适合本篇文章)。

1. 逆序添加或者删除的时候,即在集合头部添加或者删除, 会使所有new key和old key不一致,就会产生所有的dom重新渲染的情况,和没有key的效率没有啥区别。 

2. 同时使用index作为key还有产生一些bug,当使用输入类的dom时,会产生错误的dom更新

先看一下没有绑定key的情况。 

html:

  
  • {{item.id}}
  • {{item.name}}
测试

js部分代码:

const state = reactive({
  tableData1: [{
    id: 1,
    name: 'james1',
    inputValue: ''
  },{
    id: 2,
    name: 'james2',
    inputValue: ''
  },{
    id: 3,
    name: 'james3',
    inputValue: ''
  }]
})

const onTestClick = () => {
  state.tableData1.unshift({ id: state.tableData1.length + 1, name: `james${state.tableData1.length + 1}`, inputValue: '' })
}

在输入框里输入相应的值之后,界面效果如下:

vue3 不推荐使用index作为v-for遍历的key_第1张图片

点击测试按钮之后,界面效果如下图所示;

vue3 不推荐使用index作为v-for遍历的key_第2张图片

由于elementpuls组件的v-model的原因,所有的dom节点在错位后会根据具体的值重新赋值, 但是原生的输入框没有双向绑定,所以就会保持原始的dom节点上的值,由此可见,如果没有双向绑定就会出现值的错误,有双向绑定之后,由于所有的dom重新渲染赋值,界面的效率会受到影响。

下面来看一下使用index作为key会不会也有这种情况:

HTML

  
  • {{item.id}}
  • {{item.name}}
测试

JS部分保持和上文的js一致 

点击测试按钮后效果图如下:

vue3 不推荐使用index作为v-for遍历的key_第3张图片

 和没有绑定key时一样的问题。

下面来看一下绑定了唯一固定的值作为key的情况

HTML

  
  • {{item.id}}
  • {{item.name}}
测试

效果如下:

vue3 不推荐使用index作为v-for遍历的key_第4张图片

附件:diff算法的简单梳理:

  1. 经过上述我们大致知道了diff算法的流程
    1 从头对比找到有相同的节点 patch ,发现不同,立即跳出。

    2如果第一步没有patch完,立即,从后往前开始patch ,如果发现不同立即跳出循环。

    3如果新的节点大于老的节点数 ,对于剩下的节点全部以新的vnode处理( 这种情况说明已经patch完相同的vnode )。

    4 对于老的节点大于新的节点的情况 , 对于超出的节点全部卸载 ( 这种情况说明已经patch完相同的vnode )。

    5不确定的元素( 这种情况说明没有patch完相同的vnode ) 与 3 ,4对立关系。

    1 把没有比较过的新的vnode节点,通过map保存
    记录已经patch的新节点的数量 patched
    没有经过 path 新的节点的数量 toBePatched
    建立一个数组newIndexToOldIndexMap,每个子元素都是[ 0, 0, 0, 0, 0, 0, ] 里面的数字记录老节点的索引 ,数组索引就是新节点的索引
    开始遍历老节点
    ① 如果 toBePatched新的节点数量为0 ,那么统一卸载老的节点
    ② 如果,老节点的key存在 ,通过key找到对应的index
    ③ 如果,老节点的key不存在
    1 遍历剩下的所有新节点
    2 如果找到与当前老节点对应的新节点那么 ,将新节点的索引,赋值给newIndex
    ④ 没有找到与老节点对应的新节点,卸载当前老节点。
    ⑤ 如果找到与老节点对应的新节点,把老节点的索引,记录在存放新节点的数组中,
    1 如果节点发生移动 记录已经移动了
    2 patch新老节点 找到新的节点进行patch节点
    遍历结束

    如果发生移动
    ① 根据 newIndexToOldIndexMap 新老节点索引列表找到最长稳定序列
    ② 对于 newIndexToOldIndexMap -item =0 证明不存在老节点 ,从新形成新的vnode
    ③ 对于发生移动的节点进行移动处理。

vue3 不推荐使用index作为v-for遍历的key_第5张图片

 diff算法引自:vue3.0 diff算法详解(超详细)_zl_Alien的博客-CSDN博客_vue3的diff算法

你可能感兴趣的:(Vue3,前端,vue3)