XingYun blog
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具

XingYun

冲!
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具
  • 3个提升Vue性能的写法
  • 重读Vue文档
  • moment.js给定时间获取自然月、周的时间轴
  • Vue虚拟dom与Diff算法
  • 深入响应式原理
  • Echart样例
  • 我的Vue指令库
  • 滚动到底部加载更多
  • 实现一键换肤
  • 手写Vue数据劫持
  • vue-router核心原理与手写实现
  • computed和watch
  • vue数组为什么不是响应式
  • v-for为什么不能用index做key
    • v-for为什么不能用index做key
      • 一、key的作用
      • 二、为什么v-for不建议使用index做key
  • webpack loader和plugin
  • keep-alive组件原理
  • vue插槽进化
  • Vue多层嵌套组件
  • vue生命周期hook
  • vue监听dom元素的resize事件
  • 前端打包需要gzip压缩吗
  • 实现水波浪进度球
  • Vue
XingYun
2021-12-01
目录

v-for为什么不能用index做key

# v-for为什么不能用index做key

# 一、key的作用

vue官网描述

key 特殊 attribute 主要用做 Vue 的虚拟 DOM 算法的提示,以在比对新旧节点组时辨识 VNodes。如果不使用 key,Vue 会使用一种算法来最小化元素的移动并且尽可能尝试就地修改/复用相同类型元素。而使用 key 时,它会基于 key 的顺序变化重新排列元素,并且 key 不再存在的元素将始终被移除/销毁。有相同父元素的子元素必须有唯一的 key。重复的 key 会造成渲染错误。

有关虚拟dom和diff算法可以参考我的这篇博客Vue虚拟DOM和Diff算法 (opens new window),里面详细介绍了diff过程中key的作用

其中vue用来判断节点是否相同的方法中,第一步就是对比的key是否相同

function sameVnode (a, b) {
  return (
    a.key === b.key &&  // key值
    a.tag === b.tag &&  // 标签名
    a.isComment === b.isComment &&  // 是否为注释节点
    // 是否都定义了data,data包含一些具体信息,例如onclick , style
    isDef(a.data) === isDef(b.data) &&  
    sameInputType(a, b) // 当标签是<input>的时候,type必须相同
  )
}
1
2
3
4
5
6
7
8
9
10

如下列表:第二行的F为新插入的元素,当有key的情况下,diff算法只需要一次插入操作即可完成更新过程,

而如果没有key,那么从cf对比开始,要进行三次更新,一次插入操作

很明显,key提高了diff过程的效率

# 二、为什么v-for不建议使用index做key

以下一种常见场景

<div class="list"  :style="{background:item.color}" v-for="(item, index) in list" :key="index">
  	<a-input style="width:200px" :defaultValue="item.color"></a-input>
        <a-button @click="del(index)">删除</a-button>
</div>


<script>
 list = [{ color: 'red' }, { color: 'blue' }, { color: 'black' }, { color: 'green' }]
  del(index) {
    this.list.splice(index, 1)
  }
</script>
1
2
3
4
5
6
7
8
9
10
11
12

效果

![](https://gcy-1306312261.cos.ap-chengdu.myqcloud.com/blog/Dec-01-2021 11-12-31.gif)可以看到 明明我们删除的是第一行,可是为什么第一行的输入框一直是red,它一直都没被删掉。

这里有三个重要的点

  1. 当我们删除第一行,数据发生了变化,数据变化驱动视图层变化,list的长度变为2,那么只剩下了key=0 1 2的节点。

​ 原先存在key=0的节点,vue的复用策略会让继续复用这个节点,所以第一行的节点一直都没被删除。

  1. 有时候我们视图上看不出来,是因为我们组件的props和data的数据关联起来了,如这个例子的背景色,看起来是正常的符合删除逻辑的,但是它只是绑定了正确的props,props值改变又触发了一次render过程,导致背景色渲染成了正确的样子。

    同理如果是绑定的文本,vue也做了单独处理,直接单纯替换原先的文本节点,所以也会是看起来一切正常的假象

  2. input框因为值没有被双向绑定,只是设定了一个初始值,所以没有触发像background,文本一样的render更新,

所以在我们绑定key值的时候应该尽量使用唯一值,比如后端数据接口返回的id。

我们上面的例子做简单改动

<div class="list"  :style="{background:item.color}" v-for="(item, index) in list" :key="index + item.color">
  	<a-input style="width:200px" :defaultValue="item.color"></a-input>
        <a-button @click="del(index)">删除</a-button>
</div>
1
2
3
4

key绑定成了index + item.color,在这个上下文中成了唯一key

![](https://gcy-1306312261.cos.ap-chengdu.myqcloud.com/blog/Dec-01-2021 11-14-15.gif)

nice

#vue
上次更新: 2023/04/05, 09:41:10
vue数组为什么不是响应式
webpack loader和plugin

← vue数组为什么不是响应式 webpack loader和plugin→

最近更新
01
JavaScript-test
07-20
02
二维码的原理
07-20
03
利用ChatGPT优化代码
07-20
更多文章>
Theme by Vdoing | Copyright © 2021-2023 XingYun | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式