• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

vue为什么v-for指令的 key 值不能是 index

武飞扬头像
PHP中文网
帮助14

学新通技术网

为什么 v-for 的 key 值不能是 index?

很多人一说起这道老生常谈的面试题,马上就开始滔滔不绝地讲述 虚拟DOMdiff算法 了。

讲这些没问题,但如果是我,一定先讲 v-for 的 key 值写成 index 会造成的问题,再讲原理。

曾经我写 v-for, key 值永远都是 index,直到有一天,我这么写造成了线上bug...

来看一下我的线上bug演示吧:

父组件代码
<Child
  v-for="(item, index) in list"
  :key="index"
  :count="item.count"
  :name="item.name"
  @delete="handleDelete(index)"
/>

list: [
    {
      count: 1,
      name: '第1个元素'
    },
    {
      count: 2,
      name: '第2个元素'
    },
    {
      count: 3,
      name: '第3个元素'
    }
  ]
  
handleDelete(index) {
  this.list.splice(index, 1)
},

学新通技术网

如代码和gif演示,点击删除第2个元素,看上去似乎一切正常。

等一下,第三个元素的count值居然变成了2,wtf!!!

惊得我又去看了遍子组件的代码

子组件
<div>
  <span>{{ name }}</span>
  count值为:{{ innerCount }}
  <button @click="$emit('delete')">-</button>
</div>

props: {
  count: {
    type: Number,
    default: 0
  },
  name: {
    type: String,
    default: ''
  }
},
data() {
  return {
    innerCount: this.count
  } 
}

感觉也没什么不对的啊。

不信邪,我又多创建了点元素来删除,还试了下排序:

学新通技术网

果然,不光删除元素有问题,排序也有问题。

把 key 值改成 item.name 再试一下。

<Child
  v-for="(item, index) in list"
  :key="item.name"
  :count="item.count"
  :name="item.name"
  @delete="handleDelete(index)"
/>

学新通技术网

正常了。

这样看来,在 v-for 里把 key 值写成 index,非常危险啊。

在查阅了 vue 官方文档之后,我终于明白了原因:

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

这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出

不依赖子组件状态

子组件里有一行很关键的代码

data() {
  return {
    innerCount: this.count
  } 
}

子组件内部定义了 innerCount,这样子组件就有了自己的状态,按照官方文档的说明,这种情况下不能把 index 作为 key 值。

临时 DOM 状态

<div v-for="(item, index) in list1" :key="index">
  <input type="text" />
  <button @click="delClick(index)">删除</button>
</div>

学新通技术网

删除了第2项,但是第3项在表单中的3变成了2,跟上面依赖子组件状态的例子是一样的。

总结

写列表渲染时, 依赖子组件状态或临时 DOM 状态的情况,如果有 删除、增加、排序这样的功能,不要把 index 作为 key。

事实上,写列表渲染时,永远不要把 index 做为 key,key 一定要是唯一标识。

至于原因,就要理解 diff 算法之后才能明白了。

待解答问题:

  • key 为什么不能写成随机数或时间戳?
  • key 为什么要是唯一标识?

别着急,立了个写100个 vue 问题相关文章的 flag 呢,后面的文章再慢慢分析。

希望我的 vue 系列文章能对前端路上的你有帮助~

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tangbiefg
系列文章
更多 icon
同类精品
更多 icon
继续加载