Vue列表渲染的坑:为什么不能用index当key?血泪教训总结!

前言

大家好,我是小杨,一个写了6年前端的老司机。今天要聊一个Vue里看似简单但90%新手都会踩的坑------用index当key。这玩意表面人畜无害,实际暗藏杀机,轻则数据错乱,重则性能爆炸。不信?往下看我的翻车实录!


一、index当key的灾难现场

上周我写了个代办事项列表,代码长这样:

html 复制代码
<!-- 天真无邪的写法 -->
<ul>
  <li v-for="(todo, index) in todos" :key="index">
    {{ 我 }}的任务:{{ todo.text }}
  </li>
</ul>

看起来没问题对吧?直到我加了删除功能...

翻车过程:

  1. 假设有三个任务:["买菜", "写代码", "摸鱼"]

  2. 删除第二个"写代码"后

  3. Vue根据index认为:

    • 旧节点0(买菜)→ 新节点0(买菜) ✔
    • 旧节点1(写代码)→ 新节点1(摸鱼) ❌
    • 旧节点2(摸鱼)→ 被删除

结果:本该显示["买菜", "摸鱼"],却可能触发组件异常复用,导致:

  • 输入框状态错乱
  • 动画效果错位
  • 控制台疯狂警告

二、为什么index是万恶之源?

1. 数组变异操作直接暴击

  • 当发生删除/插入时,所有后续元素的index全变了
  • 但Vue觉得:"咦,key=1的节点还在嘛(其实内容已经物是人非)"

2. 性能杀手

看这个例子:

js 复制代码
// 初始数据
const todos = [
  { id: 1, text: "买菜" },
  { id: 2, text: "写代码" }
]

// 头部插入新任务
todos.unshift({ id: 3, text: "开会" })

用index当key时:

  • 所有
  • 的key都变了(0→1, 1→2)
  • 导致全部DOM重新渲染(其实只需要在头部加一个DOM)

用id当key时:

  • 只有新加的
  • 会创建
  • 其他DOM原地复用

三、正确姿势指南

✅ 方案1:用数据唯一标识

html 复制代码
<li v-for="todo in todos" :key="todo.id">
  {{ todo.text }}
</li>

✅ 方案2:实在没id怎么办?

js 复制代码
// 方法1:前端生成唯一ID
todos.map(todo => ({
  ...todo,
  _id: Math.random().toString(36).slice(2)
}))

// 方法2:用内容哈希(仅限内容不会重复)
:key="hash(todo.text)"

❌ 这些情况千万别用index!

  • 列表有增删操作
  • 列表项包含表单元素
  • 需要过渡动画
  • 列表项是有状态组件

四、血的教训

去年我们项目有个诡异bug:

  1. 表格允许拖拽排序
  2. 每行有个计数器组件
  3. 拖拽后计数器的值会随机交换

排查三天发现 :有人写了:key="index"。改成:key="row.id"后,世界和平了。


五、总结

  • 🚫 index当key ≈ 埋地雷
  • 唯一id当key = 稳如老狗
  • 💡 没有id就创造id(但别用index!)

下次写v-for时,记得摸摸头顶------哦不,记得检查key!你的头发会感谢你。

⭐ 写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

✅ 一起探讨技术加qq交流群:906392632

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

相关推荐
伍哥的传说1 小时前
Radash.js 现代化JavaScript实用工具库详解 – 轻量级Lodash替代方案
开发语言·javascript·ecmascript·tree-shaking·radash.js·debounce·throttle
程序视点2 小时前
IObit Uninstaller Pro专业卸载,免激活版本,卸载清理注册表,彻底告别软件残留
前端·windows·后端
前端程序媛-Tian2 小时前
【dropdown组件填坑指南】—怎么实现下拉框的位置计算
前端·javascript·vue
iamlujingtao2 小时前
js多边形算法:获取多边形中心点,且必定在多边形内部
javascript·算法
嘉琪0012 小时前
实现视频实时马赛克
linux·前端·javascript
烛阴3 小时前
Smoothstep
前端·webgl
若梦plus3 小时前
Eslint中微内核&插件化思想的应用
前端·eslint
爱分享的程序员3 小时前
前端面试专栏-前沿技术:30.跨端开发技术(React Native、Flutter)
前端·javascript·面试
超级土豆粉3 小时前
Taro 位置相关 API 介绍
前端·javascript·react.js·taro
若梦plus3 小时前
Webpack中微内核&插件化思想的应用
前端·webpack