vue中使用v-for时为什么不能用index作为key

结论:

  • 更新DOM的时候会出现性能问题
  • 会发生一些状态bug
  • React 中的 key 也是如此
  • 如果已经了解 为什么要用key,可以通过目录直接跳到下一节。

为什么要用key?

Vue 和 React 都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面。而隐藏在背后的原理便是其高效的Diff算法。

Vue 和 React 的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设:

  1. 两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构。
  2. 同一层级的一组节点,他们可以通过唯一的id进行区分。

基于以上这两点假设,使得虚拟DOM的Diff算法的复杂度从O(n^3)降到了O(n)。

用一张图简单说明一下:

当页面的数据发生变化时,Diff算法只会比较同一层级的节点:

如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点。

如果节点类型相同,则会重新设置该节点的属性,从而实现节点的更新。

举个栗子:

我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:

即把C更新成F,D更新成C,E更新成D,最后再插入E,这样效率不高,且性能不够好。

但是,如果使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置区插入新的节点。

总而言之,key的作用主要是为了高效的更新虚拟DOM 。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。

这里,也建议尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单。

为什么不能用index作为key?

举个栗子:

<template>
  <div v-for="(item, index) in list" :key="index" >{{item.name}}</div>
</template>
const list = [
  {
    id: 1,
    name: "Person1"
  },
  {
    id: 2,
    name: "Person2"
  },
  {
    id: 3,
    name: "Person3"
  },
  {
    id:4,
    name:"Person4"
  }
];

此时,删除 “Person4” 是正常的,但是如果我删除 “Person2” 就会出现问题。

删除前

key id index name
0 1 0 Person1
1 2 1 Person2
2 3 2 Person3
3 4 3 Person4

删除后

key id index name
0 1 0 Person1
1 3 1 Person3
2 4 2 Person4

这个时候,除了 Person1 之外,剩下的 Person3、Person4,因为被发现与相应 key 的绑定关系有变化,所以被重新渲染,这会影响性能。
如果此时 list 的 item 是 select 的选项,其中 Person3 是选中的,这个时候 Person2 被删除了,用 index 作为 key 就会变成是 Person4 选中的了,这就产生了bug。

如果使用唯一id作为key,删除 Person2 后,剩下的元素因为与 key 的关系没有发生变化,都不会被重新渲染,从而达到提升性能的目的。此时,list 的 item 作为 select 的选项,也不会出现上面所描述的bug。

到此这篇关于vue中使用v-for时为什么不能用index作为key的文章就介绍到这了,更多相关vue v-for不能用index作为key内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解为什么Vue中不要用index作为key(diff算法)

    前言 Vue 中的 key 是用来做什么的?为什么不推荐使用 index 作为 key?常常听说这样的问题,本篇文章带你从原理来一探究竟. 另外本文的结论对于性能的毁灭是针对列表子元素顺序会交换.或者子元素被删除的特殊情况,提前说明清楚,喷子绕道. 本篇已经收录在 Github 仓库,欢迎 Star: https://github.com/sl1673495/blogs/issues/39 示例 以这样一个列表为例: <ul> <li>1</li> <li>

  • 浅谈Vue2.0中v-for迭代语法的变化(key、index)

    今天,在写关于Vue2.0的代码中发现 $key这个值并不能渲染成功,问题如下: 结果这个对象的key值并不能够显示: 后来查阅了文档才知道,这是因为在Vue2.0中,v-for迭代语法已经发生了变化: 丢弃了: 新数组语法 value in arr (value, index) in arr 新对象语法 value in obj (value, key) in obj (value, key, index) in obj 解决后: 以上这篇浅谈Vue2.0中v-for迭代语法的变化(key.i

  • vue2.0移除或更改的一些东西(移除index key)

    一.vue2.0移除了$index和$key 虽然说现在很多文章说他们的代码是vue2.0版本的,但是有一些仔细一看,发现并不全是2.0版本,有些语法还是1.0的版本,比如这个$index,$key,这两个压根就不是2.0的写法,2.0早就把这两个给删除了,我们先来看看之前的列表渲染是怎么写的 <template> <div class="hello"> <ul> <li v-for="item in list">{{

  • Vue中消息横向滚动时setInterval清不掉的问题及解决方法

    最近在做项目时,需要进行两个组件联动,一个轮询获取到消息,然后将其传递给另外一个组件进行横向滚动展示,结果滚动的速度越来越快.这里记录一下来提醒自己.消息滚动的代码在最下面,方便下次使用. 问题背景: 最近在做一个需求,组件A获取消息采用的是轮询,组件A获取到新的消息后,将组件A中的消息传递给另外一个组件B,当组件B接收到消息时就让消息在页面上滚动播放. 实现思路: 这个项目应用的框架为VUE,当组件A获取到新的消息之后,就触发中央事件总线,在组件B中进行事件监听,将其添加进入一个数组,当判断定

  • vue中使用element组件时事件想要传递其他参数的问题

    在使用element的上传组件时在一下几个钩子中传递其他参数 图中是文件上传时的几个钩子,参数为文件或文件列表或者其他参数,但是现在我想在原有参数上传递其他参数.比如我想在on-success的钩子中传递一个自定义参数i,原本是这样写的: :on-success="handleSuccess(i)" //handleSuccess是一个方法 但是发现这样写取不到自身原来的参数,后来在网上找到了一个比较好的方法,如下: :on-success="(value)=> han

  • 在Vue中获取组件声明时的name属性方法

    在实际开发中,我们可能需要拿到组件声明时创建的一些属性,比较典型的话就是name属性,在实际开发中需要定位问题时,需要找到是哪一个组件,但是我们总不可能写代码的时候去先找到组件的name属性,然后复制粘贴,作为参数传给函数吧. 例如: catchError('componentsName', 'errorDescription') 太傻了. 解决办法,获取到组件的this,然后利用this去拿到组件的name属性,这样的话,代码就可以这么写: catchError.call(this, 'err

  • vue中使用v-for时为什么不能用index作为key

    结论: 更新DOM的时候会出现性能问题 会发生一些状态bug React 中的 key 也是如此 如果已经了解 为什么要用key,可以通过目录直接跳到下一节. 为什么要用key? Vue 和 React 都实现了一套虚拟DOM,使我们可以不直接操作DOM元素,只操作数据便可以重新渲染页面.而隐藏在背后的原理便是其高效的Diff算法. Vue 和 React 的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设: 两个相同的组件产生类似的DOM结构,不同的组件产生不同的DOM结构. 同一

  • 浅谈vue中组件绑定事件时是否加.native

    组件绑定事件时 1. 普通组件绑定事件不能添加.native, 添加后事件失效 2. 自定义组件绑定事件需要添加.native, 否则事件无效 <template> <!-- <mt-field label="用户名" placeholder="请输入用户名"></mt-field> --> <input type="text" @keyup.native="show($event)

  • Vue中关闭弹窗组件时销毁并隐藏操作

    背景:在dialog弹窗组件中执行mounted钩子,将数据初始化,等取消关闭弹窗后,发现mounted钩子不执行 原因:在vue的生命周期中,在页面初始化的时候mounted只会执行一次,关闭弹窗页面并没有销毁,所以不会再次执行 <select-experience-group :trialMoneyRecordID=trialMoneyRecordID :showExperienceGroup='showExperienceGroup' @closeCover="handleExper

  • 在Vue中使用echarts的实例代码(3种图)

    前言 公司的项目中需要对数据做可视化处理,高级点的D3.js目前还没接触到,因此选用了大众化的Echarts, 在vue的生态系统中已经有实现好的vue-echarts,但是使用现成的就意味着必须使用它定制好的数据结构,我也没办法对他进行一些修改.我个人也偏向于原生JS编程,因此没有采用,而是自己在vue中实现了对数据的可视化处理,先来看看效果图 以下数据已做脱敏处理 这是目前用到的三种图. 可以看到,我在图表的外部添加了标题及说明,以及右侧的选择框组件,视图可以根据选择的不同,图表进行动态切换

  • Vue中"This dependency was not found"问题的解决方法

    今天在初始化项目中,出现了一个奇怪的情况:明明路径是对的,但是编译的时候,一直报"This dependency was not found"的错. 代码如下: import Vue from 'vue' import App from './App' import router from './router' import 'common/stylus/index.styl' /* eslint-disable no-new */ new Vue({ el: '#app', rend

  • 在 Vue 中使用 JSX 及使用它的原因浅析

    本文 GitHub https://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料.欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西. Vue.js 具有简单的 API 和几个选项,可用于在我们的组件中定义HTML模板. 我们可以使用 <template> 标签选项,在根组件实例上定义 template 属性,或者使用单文件组件. 上面的选项很棒并且可以完美地工作,但是,在您的应用程序的生命周期中,有时会

  • vue中提示$index is not defined错误的解决方式

    今天学习Vue中遇到了一个报错信息:$index is not defined,是我写了个for循环在HTML中,然后是因为版本的问题 下面是解决方法: 原来的是 v-for="person in items" v-on:click="deletePerson($index)"//这个仅仅适用于1.0版本,不要采坑了同学们 这个在Vue1.0版本中式适用的可以直接使用$index,但是在2.0是不适合的 在Vue 2.0版本中获取索引我们需要通过 v-for = &

随机推荐