vue的v-for循环key属性为什么不能用index?

html 复制代码
const list = ref([
    {
      id:1,
      text:"aaa"
    },{
      id:2,
      text:"bbb"
    },{
      id:3,
      text:"ccc"
    }
])
html 复制代码
  <ul>    <li v-for="(item, index) in list"  >{{ item.text }}</li>  </ul>

以上代码运行后,渲染出来是这样的:

然后我们给list的末尾加一个新元素:

php 复制代码
  list.value.push({      id:100,      text:"ddd"  })

加上新元素后,页面展示如下

其实一开始,是有一个虚拟dom列表的,list增加新元素后,又会生成一个新的虚拟dom列表

新旧虚拟dom列表如下,左边的旧的,右边是新的

创建新虚拟dom列表后,与旧的虚拟dom比较,上图种,左边第0个与右边第0个是一样的,所以真实dom里的第0个li不变,

左边第1个与右边第1个是一样的,所以真实dom里的第1个li不变,

左边第2个与右边第2个是一样的,所以真实dom里的第2个li不变

右边有第三个,左边没有第三个,所以会在真实dom列表里新创建一个dom,里面显示ddd

接下来,看看另一种案例:

php 复制代码
const list = ref([    {      id:1,      text:"aaa"    },{      id:2,      text:"bbb"    },{      id:3,      text:"ccc"    }])
xml 复制代码
  <ul>    <li v-for="(item, index) in list"  >{{ item.text }}</li>  </ul>

运行后页面如下:

然后,我们在list的index为1的位置插入一个新元素

php 复制代码
  list.value.splice(1, 0 ,{      id:100,      text:"ddd"  })

然后页面显示如下:

往list里插入新元素后,新旧虚拟dom列表可以表示如下

然后vue会比较新旧列表

左边第0个与右边第0个是一样的,所以真实dom里的第0个li不变,

左边第1个与右边第1个不一样,所以真实dom里的第1个li会被修改,

左边第2个与右边第2个不一样,所以真实dom里的第2个li会被修改,

右边有第三个,左边没有第三个,所以会在真实dom列表里新创建一个dom,里面显示ccc

我们可以看到,往list里插入新元素后,真实dom里的第1个到第二个li都更新了,这样性能太差了

接下来,再写一个案例,给v-for加key


php 复制代码
const list = ref([    {      id:1,      text:"aaa"    },{      id:2,      text:"bbb"    },{      id:3,      text:"ccc"    }])
css 复制代码
  <ul>    <li v-for="(item, index) in list" :key="item.id" >{{ item.text }}</li>  </ul>

注意,这里我给li加了个key属性,值为item.id

运行后页面是这样的:

然后,我们在list的index为1的位置插入一个新元素

php 复制代码
  list.value.splice(1, 0 ,{      id:100,      text:"ddd"  })

然后页面显示如下:

新虚拟dom列表和旧虚拟dom列表可以表示如下:

这次,他们是有key属性的,在有key属性的情况下,新旧虚拟dom的比较过程是这样的:

key为0的旧虚拟dom和key为0的新虚拟dom一样,

key为1的旧虚拟dom和key为1的新虚拟dom一样,

key为2的旧虚拟dom和key为2的新虚拟dom一样

所以真实dom里的这三个li不会改变

新的虚拟dom列表里多了一个key为100的虚拟dom,并且在索引为1的位置

所以vue会在真实的dom里,索引为1的地方插入一个新的li,li里的内容是ddd

看到没,这次不像上一个案例里那样改变了2个li,这次只要增加一个li,原来的三个li完全不用改变,性能是不是比较好了

用index作为key

接下来,说说如果用index来作为key,会怎么样

php 复制代码
const list = ref([    {      id:1,      text:"aaa"    },{      id:2,      text:"bbb"    },{      id:3,      text:"ccc"    }])
css 复制代码
  <ul>    <li v-for="(item, index) in list" :key="index" >{{ item.text }}</li>  </ul>

运行后页面是这样的:

然后,我们在list的index为1的位置插入一个新元素

php 复制代码
  list.value.splice(1, 0 ,{      id:100,      text:"ddd"  })

然后页面显示如下:

新虚拟dom列表和旧虚拟dom列表可以表示如下:

他们是有key属性的,在有key属性的情况下,新旧虚拟dom的比较过程是这样的:

key为0的旧虚拟dom和key为0的新虚拟dom一样,所以真实dom里的第0个li不用改变

key为1的旧虚拟dom和key为1的新虚拟dom不一样,所以真实dom里的第1个li要改变

key为2的旧虚拟dom和key为2的新虚拟dom不一样,所以真实dom里的第2个li要改变

新的虚拟dom列表末尾多了一个key为3的虚拟dom,所以在真实li列表末尾创建一个新的li

你看,这样bbb和ccc这两个li都需要被改变,跟上一个案例比较一下,这次改变的真实dom比较多,所以不能用index来作为key的值

相关推荐
乐无止境3 分钟前
系统性整理组件传参14种方式
前端
爱泡脚的鸡腿4 分钟前
uni-app D8 实战(小兔鲜)
前端·vue.js
睡神雾雨6 分钟前
Vite 环境变量配置经验总结
前端
咪库咪库咪6 分钟前
vue5
前端
前端缘梦6 分钟前
JavaScript核心机制:执行栈、作用域与this指向完全解析
前端·javascript·面试
Larry_zhang双栖7 分钟前
解决 Figma MCP 下载图片卡死问题:从踩坑到自研 npm 工具全记录
前端·npm·figma
JarvanMo7 分钟前
Flutter 3.38 动画新特性:动画引擎有什么新变化?
前端
ByteCraze11 分钟前
CDN 引入 与 npm 引入的区别
前端·npm·node.js
Youyzq11 分钟前
react 元素触底hooks封装
前端·javascript·react.js
crary,记忆12 分钟前
PNPM 和 NPM
前端·学习·npm·node.js