必须为 v-for 设置稳定、唯一、基于数据的 key(如 item.id),禁用 index、随机数和时间戳;嵌套结构需分层设 key;无真实 id 时应一次性生成并持久化临时 id;配合虚拟滚动等策略优化长列表性能。

给 v-for 加上稳定、唯一、基于数据的 key,是解决列表渲染错乱、输入状态丢失、动画中断和性能抖动的根本前提。它不是“锦上添花”,而是 Vue 正确 diff 和复用节点的硬性要求。
必须用业务 ID,禁用 index、随机数和时间戳
key 的本质是虚拟节点(vnode)的身份证。Vue 依赖它精准匹配新旧节点,避免误复用。
- 用
:key="item.id"(后端返回的主键或 UUID)——最可靠,数据不变 key 就不变 - 禁用
:key="index":一旦插入/删除/排序,索引重排,Vue 会把“香蕉”当成“苹果”复用,导致表单内容跳变、checkbox 状态错位 - 禁用
:key="Date.now()"或:key="Math.random()":每次渲染 key 都变,Vue 强制销毁重建所有节点,输入框清空、过渡动画重播、组件实例反复创建销毁
嵌套列表与动态结构要分层设 key
树形菜单、可折叠分组、Tab 切换下的列表,每一层循环都需独立且稳定的 key 锚点。
- 父级用
:key="category.id",子项用:key="`${category.id}-${item.id}`",不拼接无意义字段 - 当同一位置需切换不同组件(如编辑态/展示态),把 key 放在最外层容器上,确保状态锚点不随结构切换而丢失
- 若子组件封装了
v-for,key 必须加在组件标签本身(<usercard v-for="u in users" :key="u.id"></usercard>),而非组件内部某个 div
没有真实 ID?前端打标要一次且恒定
后端未返回稳定 ID 时,不能每次响应式更新都重生成 key,否则等于没设。
- 首次加载 API 数据后,用
crypto.randomUUID()或nanoid()为每项一次性添加临时 ID,并存入响应式数据中 - 避免用
Symbol()(非字符串,Vue 控制台会警告)或index + timestamp(timestamp 可能重复) - 组合字段生成 key 时,确保结果全局唯一,例如
:key="item.email + '-' + item.createdAt",但优先推动后端补全真实 ID
配合其他优化手段应对长列表抖动
key 是基础,但面对成百上千项的列表,还需叠加策略降低渲染压力:
- 启用虚拟滚动(如
vue-virtual-scroller),只渲染可视区域 DOM,大幅减少节点数量 - 避免
v-for与v-if同级连用,改用计算属性预筛数据,防止每次遍历都执行条件判断 - 对复杂子组件使用
defineAsyncComponent或v-memo(Vue 3.2+)缓存静态块,减少重复 patch









