vue中列表渲染有key与没有key的区别

2021-08-24  本文已影响0人  小十一eleven

当 Vue 使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这句话是什么意思呢,看一下图你就会理解:


数据由[A,B,C,D]改变成了[A,E,C,D]的过程。 数据由[A,B,C,D]改变成了[E,A,B,C,D]的过程。

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为什么这么说呢,运行一下以下代码你就会发现问题:

  <div>
    <input type="text" v-model="name">
    <button @click="add">添加</button>
  </div>
  <div v-for="name in list">
    <input :id="name" type="radio" name="name" :value="name" v-model="checkedNames">
    <label :for="name">{{name}}</label>
  </div>
  <div>Checked names: {{ checkedNames }}</div>
data() {
    return {
        name: '',
        list: ['张三', '李四', '王五'],
        checkedNames: []
      }
},
methods: {
   add() {
      this.list.unshift(this.name);
   }
 }
先选中“张三” 添加“十一”

从上面我们发现,开始选中的张三,当添加一个十一后,虽然选中的值显示张三,但页面展示却选中了十一,这显然是错误的,这就是就地更新造成的错误。
当我们给代码加上key时,问题就解决了(添加时保证name的唯一性)。

<div>
    <input type="text" v-model="name">
    <button @click="add">添加</button>
  </div>
  <div v-for="name in list" :key="name">
    <input :id="name" type="radio" name="name" :value="name" v-model="checkedNames">
    <label :for="name">{{name}}</label>
  </div>
  <div>Checked names: {{ checkedNames }}</div>
image.png

key的作用主要用在 Vue 的虚拟 DOM 算法,给 Vue 一个提示,以便能跟踪每个节点的身份,从而重用和重新排序现有元素,移除 key 不存在的元素(并且根据源码可以看出,在比较新老节点首尾节点交叉进行sameVnode比对都不相同时,有key后续的比对会更快,通过map可以快速定位,不需要去遍历老节点sameVnode寻找)。

数据由[A,B,C,D]改变成了[E,A,B,C,D]的过程。 数据由[A,B,C,D]改变成了[A,E,C,D]的过程。

如有不正确的地方,欢迎指正。

上一篇 下一篇

猜你喜欢

热点阅读