在vue中,为什么不能用index作为key?

news2024/12/24 7:17:44

啊?不是吧,在vue中,不能使用index作为key呢?使用index作为key又好理解又方便,为什么不能使用呢?看文章就知道啦~.

一、key的作用是什么?

key的作用众所周知,看一个demo就知道:

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<body><ul id="app"><li v-for="(item,index) in list" :key="index">{{item}}</li></ul>
​<script> new Vue({el: '#app',data() {return {list: [1, 2, 3]}}}) </script>
</body> 

在vue中key可以没有,没有也可以运行并且不会报错,但是建议加上key。

另外,我们必须知道,vue中key运用的地方------配合v-for使用。key是vue中虚拟dom标记的唯一标识,通过这个key,diff算法能更加准确和快捷。不使用key的情况下,因为vue的就地更新会选择复用节点,之前的状态被保存,可能会产生一系列的bug。另外,key的唯一性可以被map数据结构充分利用,时间复杂度仅为o(1)。

简单来说,key是唯一标识,为了让diff算法更准确的找到需要被对比的两个节点。

二、什么是虚拟DOM?

虚拟DOM结构就是一个对象而已,其中描述了每一层容器的特征。在beroreCreated执行的时候,DOM树并没有生成。

虚拟DOM光说肯定是不可理解的,那我们就用代码说话:

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<body><div id="app"><ul><item v-for="(num,index) in list" :key="index":num="num":class=`item${num}`></item></ul><button @click="change">change</button></div>
​<script> new Vue({el: '#app',data() {return {list: [1, 2, 3]}},methods: {change() {this.list.reverse()}},
                //也可以使用原生JS添加DOM结构,不考虑性能的时候components: {item: {props: ['num'],template: `<div>{{num}}</div>`,name: 'child'}}})            // let ul = document.getElementById('app');// for (let i = 1; i <= 3; i++) {//let li = document.createElement('li');//li.innerHTML = i;//ul.appendChild(li);// } </script></body> 

先生成虚拟DOM结构,而不是编译:

vnode = {
    tag: 'ul',
    children: [
      {
            tag: 'li',
                children: [{
                    vnode: {
                        text: '1'
                  }
              }]},
      {
            tag: 'li',
                children: [{
                    vnode: {
                        text: '2'
                  }
              }]
      },
      {
            tag: 'li',
                children: [{
                    vnode: {
                        text: '3'
                  }
              }]
      },
  ]
} 

再将html编写成真实的DOM结构:

再编译成真实DOM结构<li>1</li><li>2</li><li>3</li> 

虚拟DOM存在的意义就是,减少真实DOM结构的操作,对于浏览器来说,减少开销,提高性能

三、什么是diff算法?

只要数据源发生变化,就一定会触发watcher观察者函数(Object。defineProperty())的回调函数,去驱动视图更新,(加_是为了表明这是vue自带的方法)

回调:

vm._update(vm._render()),
_render会生成vnode
_update会拿着vnoe去__patch__去查找不同
__patch__中启动的就是diff算法 
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<body>
    <div id="app">
        <ul>
            <item v-for="(item,index) in list" :key="item.id" :num="item.num" :class=`item${item.num}`></item>
    </ul>
    <button @click="change">change</button>
</div >
    <script> new Vue({
            el: '#app',
        data() {
            return {
            list: [1, 2, 3]
      },
        methods: {
            change() {
            this.list.reverse()
      }
      },
        components: {
            item: {
            props: ['num'],
        template: `<div>{{ num }}</div>`,
        name: 'child'
          }
      }
  }) </script>
</body > 

当点击按钮change以后,list反转变为:list:[3,2,1],diff算法会根据DOM树,从上到下,从左到右判断值是否更新。问题是,为什么diff就知道谁跟谁去进行比对呢?这就是key的作用了,key是唯一标识符,diff算法会根据key去比对。

四、为什么不能用index作为key?

基于前三者的知识基础,我们才能更好地理解,为什么不能用index作为key?这里将通过三个demo来展示:

(1)index不能作为key–情景一

demo1:

 <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><body><div id="app"><ul><item v-for="(num,index) in list" :key="index" :num="num" :class=`item${num}`></item></ul><button @click="change">change</button></div><script> new Vue({el: '#app',data() {return {list: [1, 2, 3]}},methods: {change() {this.list.reverse()}},components: {item: {props: ['num'],template: `<div>{{num}}</div>`,name: 'child'}}}) </script></body> 

demo2:

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<body><div id="app"><ul><item v-for="(item,index) in list" :key="item.id" :num="item.num" :class=`item${item.num}`></item></ul><button @click="change">change</button></div><script> new Vue({el: '#app',data() {return {list: [{id: 0,num: 1}, {id: 1,num: 2}, {id: 2,num: 3}]}},methods: {change() {this.list.reverse()}},components: {item: {props: ['num'],template: `<div>{{num}}</div>`,name: 'child'}}}) </script>
</body> 

demo1与demo2的区别在于,key值不一样,demo1是index作为key,而demo2是list中的id作为key。需要注意的是,当我们点击change按钮以后,注意观察代码是如何变化的:

demo1点击前后变化:

demo2点击前后变化:

表面上,demo1只是调换了item1和item3的位置,点击后也是就改变了item1和item3;而demo2三个都改变了。这时有人就会觉得使用index作为key改动DOM结构还更小,岂不是更好?

实际上,眼见不一定为实。我们看看真实的样子:

demo1的改变前后对比:

demo2改变前后对比:

是不是震惊了!!!demo2的list实际上的key和num一一对应着,并没有改变,只是顺序不一样了。而demo1还改变了两个值。所以,这就是不能使用index作为key的原因之一了。

使用index作为key,会导致diff中的优化失效(降低了复用性,违背了虚拟DOM的初衷)。原本可以复用的东西,不能被复用,徒然增加了性能开销,浪费性能

(2)index不能作为key—情景二

接下来看看demo3,demo3将会淋漓尽致的展现index作为key的bug:

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><body><div id="app"><ul><item v-for="(item,index) in student" :key="index"></item>
              //<item v-for="(item,index) in list" :key="item.id"></item></ul>
            <button @click="change">change</button></div><script> new Vue({el: '#app',data() {return {list: [{id: 0,num: 1}, {id: 1,num: 2}, {id: 2,num: 3}],student: [1, 2, 3]}},methods: {
                    //删除数据change() {this.student.splice(0, 1)
                        //this.list.splice(0, 1)}},components: {item: {template: `<div>{{Math.random()}}</div>`,}}}) </script></body> 

当删除的时候,又会发生什么意想不到事情呢?

右图是删除之后的结果,惊讶的发现,我们_删除的明明是第一个数据,而页面展示是删除了第三个数据_。小小的脑袋真的会有大大的疑问。但是通过虚拟DOM,你就会恍然大悟了。

当用index作为key时,因为diff算法会就地更新,会复用key:0的这个节点,比对的时候,key:0的节点存在,则比对key:1,也存在,而多出了key:2,则会将其删除。

使用index作为key时,在删除数据时,因为vue不会深入地区对比子组件的文本内容,所以会错误移除VDOM中的节点(index的值是不固定的)。

这个例子,文本内容使用的是随机数,所以数据对不上不必太在意。另外,既然index的值不固定,不能作为key,那么扩展一下,可不可以使用随机数作为key呢?答案自然是不能够。因为key值无论是删除还是反转,根本就不能找到相同的key,diff算法就毫无意义了,压根没有复用性可言。

在这个demo3里,数据源放了list这个数据,可言尝试循环它,来对比index作为key的结果,将会更加明显哦。

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/95638.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【FFmpeg视频播放器开发】解封装解码流程、常用API和结构体简介(一)

一、前言 在正式编写 FFmpeg 播放器前&#xff0c;我们需要先简单了解下所要用到的 FFmpeg 库、播放与解码流程、函数和相关结构体。 二、FFmpeg 库简介 库介绍avcodec音视频编解码核心库avformat音视频容器格式的封装和解析avutil核心工具库swscal图像格式转换的模块swresa…

零基础如何学好Python?Python有哪些必须学的知识?

跟几个IT界的大佬提起Python&#xff0c;他们说零基础学好Python很简单&#xff0c;Python进阶需要花费些气力。那么零基础如何学好Python&#xff1f;Python有哪些必须学的知识&#xff1f;学习的策略技巧有哪些&#xff1f;今天小编整理的这篇文章将会给你启发。 Python上手…

vulnhub靶机DriftingBlue6

靶机下载地址DriftingBlues: 6 ~ VulnHub kali ip&#xff1a;192.168.174.128 靶机ip&#xff1a; 192.168.174.140 首先进行ip地址发现 进行端口扫描 这里进行目录扫描&#xff0c;我习惯性使用Linux里面的gobuster和Windows上的dirsearch一起进行扫描。 python dirsearc…

Linux | 常见指令和常用热键

啊我摔倒了..有没有人扶我起来学习.... &#x1f471;个人主页&#xff1a;《CGod的个人主页》\color{Darkorange}{《CGod的个人主页》}《CGod的个人主页》交个朋友叭~ &#x1f492;个人社区&#xff1a;《编程成神技术交流社区》\color{Darkorange}{《编程成神技术交流社区》…

升级Linux服务器你必须要知道的事

服务器安全是每个系统管理员的头等大事。除了拥有第三方安全工具&#xff08;如防火墙&#xff0c;DDoS保护等&#xff09;外&#xff0c;使生产服务器上的所有代码保持最新也是极为重要的。 当您的应用程序投入生产时&#xff0c;升级它的风险更大。如果您的服务器由Linux驱动…

超级简单基于nodejs电商管理系统的设计与实现.zip(论文+源码+ppt文档+视频录制)

相关资料下载地址&#xff1a;请点击下载》》》 该商城平台整体上实现了商品管理模块、订单交易模块,购物车模块、商品列表股那里模块、用户模块模块。在这些功能模块独立运行和相互配合下形成了一个电商商城系统。在商城实现的技术架构方面,该商城采用nodejs作为商城后台的底…

C++11标准模板(STL)- 算法(std::minmax)

定义于头文件 <algorithm> 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操作。注意范围定义为 [first, last) &#xff0c;其中 last 指代要查询或修改的最后元素的后一个元素。 返回两个元素的较小和较大…

二次供水智慧改造,保障冬季热水稳定供给

冬季低温雨雪天气不仅仅影响到居民用水&#xff0c;也影响到二次供水泵站的维护检修。一旦设备出现故障&#xff0c;导致无法及时供水&#xff0c;居民可能喝不上一口热水&#xff0c;更不用提热水洗澡的难题了。因此&#xff0c;在冬季需要对二次供水泵站设备更加关注&#xf…

AD20和立创EDA设计(4)PCB设计

&#xff08;1&#xff09;本文主要介绍如何将从立创EDA导出的原理图&#xff0c;在AD20进行PCB设计。 &#xff08;2&#xff09;需提前观看&#xff1a;AD20和立创EDA设计&#xff08;3&#xff09;微调原理图和原理图检查&#xff1b; &#xff08;3&#xff09;邀请加入嵌入…

【数据结构Note6】-图-知识总结(图存储+BFS+DFS+最小生成树+最短路径+拓扑+逆拓扑)

文章目录6.1 图的定义及性质6.1.1 无向图和有向图6.1.2 简单图和多重图6.1.3 图的相关概念6.1.3.1 顶点的度6.1.3.2 顶点和顶点的关系6.1.3.3 子图6.1.3.4 连通分量6.1.3.5 强连通分量6.1.3.6 生成树6.1.3.7 生成森林6.1.3.8 边的权、带权图/网6.1.3.9 几种特殊的图6.2 图的存储…

课程试题库网站

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 模块划分&#xff1a;老师模块、班级模块、学生模块、课程模块、试题模块、试卷模块、组卷模块、考试模块、答题模) 管理…

零基础转行Python开发怎么学习呢?

转行零基础学Python编程开发难度大吗&#xff1f;从哪学起&#xff1f;近期很多小伙伴问我&#xff0c;如果自己转行学习Python&#xff0c;完全0基础能否学会呢&#xff1f;Python的难度到底有多大&#xff1f;今天&#xff0c;小编就来为大家详细解读一下这个问题。 学习 Py…

时间哈希+日期处理 睡大觉

E-睡大觉_2022河南萌新联赛第&#xff08;四&#xff09;场&#xff1a;郑州轻工业大学 (nowcoder.com) 题意&#xff1a; 思路&#xff1a; 这是一道模拟题&#xff0c;这里主要总结如何处理时间信息和日期信息 对于时间信息&#xff1a;把时分秒转化成秒&#xff0c;相当…

基于java(springboot)网吧管理系统(java毕业设计)

基于java&#xff08;springboot&#xff09;网吧管理系统 网吧管理系统是基于java编程语言&#xff0c;mysql数据库&#xff0c;springboot框架和idea开发工具开发 &#xff0c;本系统分为会员&#xff0c;网管&#xff0c;管理员三个角色&#xff0c;会员功能是注册登陆系统…

基于JAVA的网上订餐外卖系统(Java+MySQL)

美食是人类永恒的话题,无论是在古代还是现代人们对美食都有一种非常的热爱在里面,但是随着时代的发展,人们可能没有更多的时间去研究美食,很多时候人们在下班或者放学之后更希望通过网络来进行订餐,为此我开发了本基于JAVA的餐必达网上订餐系统 本餐必达网上订餐系统采用Java语…

在写vue的项目中为什么index不能做key使用?

前言 在我们写vue的的项目时&#xff0c;我们是否会疑惑后端数据为什么都会带一个Id&#xff0c;而这个Id一般都作为循环中的key来使用&#xff0c;我们为什么不直接用index来作为他的key呢&#xff1f;这样不是更方便吗&#xff1f;下面我就带大家解决解决这和疑惑吧。 key的…

深度学习-归一化输入,梯度消失爆炸,梯度检验

文章目录前言一、归一化输入1、均值方差归一化2、why normalize input?二、梯度消失&#xff0c;爆炸1.梯度2.深度网络学习初始化三、梯度检验梯度检验前言 吴恩达 week5 一、归一化输入 1、均值方差归一化 均值方差归一化。 要注意&#xff1a;我们要对训练数据集和测试数…

探花交友_第9章_小视频方案(新版)

探花交友_第9章_小视频方案(新版) 文章目录探花交友_第9章_小视频方案(新版)1. 我的访客1.1 需求分析1.1.1 功能说明1.1.2 数据库表1.2 记录访客数据tanhua-modeltanhua-app-servertanhua-dubbo-interfacetanhua-dubbo-mongo1.3 首页谁看过我需求分析tanhua-modeltanhua-app-se…

小学生 C++画图 Go C 编程 第7课 奇异的花朵

第一课 GoC简介和演示 第一课 GoC简介和演示_ahwhjt的博客-CSDN博客_goc输入图形数量 第二课 了解编程环境 第二课 了解编程环境_ahwhjt的博客-CSDN博客_goc编程环境 第三课 基本绘图命令 第三课 基本绘图命令_ahwhjt的博客-CSDN博客_电脑编程的pen.lt 第四课 变量的引入 第…

重写 Nacos 服务发现:多个服务器如何跨命名空间,访问公共服务?

一、问题背景 在开发某个公共应用时&#xff0c;笔者发现该公共应用的数据是所有测试环境&#xff08;假设存在 dev/dev2/dev3&#xff09;通用的。 这就意味着只需部署一个应用&#xff0c;就能满足所有测试环境的需求&#xff1b;也意味着所有测试环境都需要调用该公共应用…