目录

1.暴露问题,使用index作为key

2.使用唯一标识p.id作为key

3.不写key的配置

4.key的工作原理及虚拟DOM的对比算法

5.总结


25.Vue列表渲染_爱米酱的博客-CSDN博客这一节开始我们来学一下Vue中与列表渲染相关的东西,这部分知识很重要,而且还比较多,所以我就拆成几个小节来讲。那么这一小节我们就先讲讲基本列表,把基本列表讲清楚之后,我们再讲key的原理,列表过滤和列表排序实现效果:讲到这里这个遍历就已经实现了,但是这里还有一个特别重要的属性,就是key,我们这里不详谈这个属性,这一节我们只关注怎么配置这个属性即可,具体的深入分析内容会在下一节呈现。和key相关的内容我们可以在Vue官网的学习-->API中找到。 这个key属性就是给遍历的每一项加了一个特殊标识,虽然https://blog.csdn.net/qq_37050372/article/details/125595515在上一节中我们讲了简单的Vue的列表渲染,那么这一节中我们就详细的探讨一下在Vue中当我们使用v-for去渲染一个列表的时候,我们传递的key有什么作用?它的原理又是什么样的?这一节也会把大家关心的几个点讲清楚,也是面试中经常会问的。1.在Vue中这个key写了它会怎么处理?要是不写Vue又会怎么处理?2.如果使用了key,那么key的值使用什么好?是使用遍历时候得索引值比较好?还是使用每个值的唯一标识id比较好?这个其实也是分情况的。接下来我们都会说明。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表渲染</title><!--引入Vue--><script type="text/javascript" src="../js/vue.js"></script><style></style>
</head>
<body><!--准备好一个容器--><div id="root"><!-- 遍历列表 --><h2>人员列表</h2><ul><li v-for="(p,index) in persons" ::key="index">{{p.name}} -- {{p.age}}</li></ul></div>
</body><script type="text/javascript">Vue.config.productionTip = false //阻止Vue在启动时生成生产提示const vm = new Vue({el:'#root',data:{persons:[{id:'001',name:'张三',age:18},{id:'002',name:'李四',age:19},{id:'003',name:'王五',age:20}]},methods: {},})</script>
</html>

在上一节的这段代码中我们最终采用的是使用index作为遍历的key(索引值),那么针对目前的这个功能来说是没问题的。

这里我们粗略的给大家说一下这个key有什么作用?这个key就是给节点一个标识,相当于人类社会中的身份证号。

接下来为了让大家理解的更加透彻,我将会通过一个反例来暴露出不使用key或者使用了不合适的key会有什么样的问题,然后再给出解决办法的方式帮助大家理解。

上一节课中,我们这个代码实现效果是这样的,那么为了暴露问题,我们这里需要再实现一个需求。点击按钮,在张三的前面添加一个老六节点。 

这里补充一个知识点:

  • push()方法可以在数组的末属添加一个或多个元素
  • shift()方法把数组中的第一个元素删除
  • unshift()方法可以在数组的前端添加一个或多个元素
  • pop()方法把数组中的最后一个元素删除
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表渲染</title><!--引入Vue--><script type="text/javascript" src="../js/vue.js"></script><style></style>
</head>
<body><!--准备好一个容器--><div id="root"><!-- 遍历列表 --><h2>人员列表</h2><button @click.once="add">添加一个老六</button><ul><li v-for="(p,index) in persons" ::key="index">{{p.name}} -- {{p.age}}</li></ul></div>
</body><script type="text/javascript">Vue.config.productionTip = false //阻止Vue在启动时生成生产提示const vm = new Vue({el:'#root',data:{persons:[{id:'001',name:'张三',age:18},{id:'002',name:'李四',age:19},{id:'003',name:'王五',age:20}]},methods: {add(){const p = {id:'004',name:'老六',age:40}this.persons.unshift(p);}},})</script>
</html>

实现效果:

这里值得注意的一个点是,我们在写模板的时候每个li都写了一个属性key,值就是遍历时候的索引值index,但是页面上生成的可用的真实DOM,却都不再拥有key属性。这是为什么呢?

这是因为这个key属性是Vue内部在使用的,我们模板上的确写了key属性,而Vue也的确用了,但是Vue在使用完之后,生成真实DOM的时候就把key去掉了。

接着说,刚刚我们实现了在张三前面添加一个老六的功能,虽然表面上看着一点问题也没有,但是它其实是存在很严重的效率问题的。后面我们会证明这个问题的存在的。

1.暴露问题,使用index作为key

接下来我们让每个人的li中,都有一个input框,用于输入各自的信息,然后重新实现刚刚添加老六的效果。我们期望的效果是添加完老六之后,它所对应的li后面会生成一个空的input框

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表渲染</title><!--引入Vue--><script type="text/javascript" src="../js/vue.js"></script><style></style>
</head>
<body><!--准备好一个容器--><div id="root"><!-- 遍历列表 --><h2>人员列表</h2><button @click.once="add">添加一个老六</button><ul><li v-for="(p,index) in persons" :key="index">{{p.name}} -- {{p.age}}<input type="text"></li></ul></div>
</body><script type="text/javascript">Vue.config.productionTip = false //阻止Vue在启动时生成生产提示const vm = new Vue({el:'#root',data:{persons:[{id:'001',name:'张三',age:18},{id:'002',name:'李四',age:19},{id:'003',name:'王五',age:20}]},methods: {add(){const p = {id:'004',name:'老六',age:40}this.persons.unshift(p);}},})</script>
</html>

实现效果:

我们可以看到这个时候诡异的事情出现了。在添加完老六之后,他们四个人后面跟着的input框出现了错位。

写到这里我就把我想要暴露的问题给大家呈现出来了?那么这个问题是怎么造成的呢?这个问题错就错在它在这种特殊的情况下使用了index作为key。这个时候有人就会有疑问,这是什么特殊情况呀?

2.使用唯一标识p.id作为key

那么接下来我们换一种写法,我们不使用index作为key,而是使用p.id,也就是每行值的唯一标识作为key,看看会不会再出现这样的问题?

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表渲染</title><!--引入Vue--><script type="text/javascript" src="../js/vue.js"></script><style></style>
</head>
<body><!--准备好一个容器--><div id="root"><!-- 遍历列表 --><h2>人员列表</h2><button @click.once="add">添加一个老六</button><ul><li v-for="(p,index) in persons" :key="p.id">{{p.name}} -- {{p.age}}<input type="text"></li></ul></div>
</body><script type="text/javascript">Vue.config.productionTip = false //阻止Vue在启动时生成生产提示const vm = new Vue({el:'#root',data:{persons:[{id:'001',name:'张三',age:18},{id:'002',name:'李四',age:19},{id:'003',name:'王五',age:20}]},methods: {add(){const p = {id:'004',name:'老六',age:40}this.persons.unshift(p);}},})</script>
</html>

实现效果:

从上面的效果来看,我们用每行的唯一标识作为key是正常的。

3.不写key的配置

那如果我们连key都不写了,又会是什么样的效果呢?我们再试试

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>列表渲染</title><!--引入Vue--><script type="text/javascript" src="../js/vue.js"></script><style></style>
</head>
<body><!--准备好一个容器--><div id="root"><!-- 遍历列表 --><h2>人员列表</h2><button @click.once="add">添加一个老六</button><ul><li v-for="(p,index) in persons" >{{p.name}} -- {{p.age}}<input type="text"></li></ul></div>
</body><script type="text/javascript">Vue.config.productionTip = false //阻止Vue在启动时生成生产提示const vm = new Vue({el:'#root',data:{persons:[{id:'001',name:'张三',age:18},{id:'002',name:'李四',age:19},{id:'003',name:'王五',age:20}]},methods: {add(){const p = {id:'004',name:'老六',age:40}this.persons.unshift(p);}},})</script>
</html>

实现效果:

我们可以看到不使用key,也会有问题。

4.key的工作原理及虚拟DOM的对比算法

综上所述,我们可以看到,当我们使用index作为key,或者不使用key的时候,都会有问题,而只有我们使用唯一标识p.id的时候才会正常。

如果我们 想把这个问题讲清楚,就一定要了解两个东西,key的工作原理还有虚拟DOM的对比算法

接下来我们就详细讲解一下其中的细节

当使用index作为key的时候

首先在我们准备好数据之后,Vue会拿着我们的数据生成虚拟DOM,然后再将虚拟DOM转为真实的DOM。表现图如下:

这里要格外的注意,用户是在真实DOM中输入内容的,而虚拟DOM是在内存里得,虚拟DOM是用户无法操作的。用户能操作的都是真实DOM。

接下来我们再看看数据更新的情况:

我们在所有人的前面添加了一个老六,那么Vue就会根据新数据生成虚拟DOM,而此时生成的虚拟DOM中老六的key就变成0了,而张三,李四,王五的key都依次顺延了一位。

那么接下来又会发生什么呢?有的同学这时候就会说,那应该和刚才一样呀,直接把新生成的虚拟DOM转为真实DOM就行了。

那如果是这样的话,Vue所使用的这个虚拟DOM的环境不就啥用也没有了嘛?反而还多了一个中间环节。浪费了很多时间。所以Vue其实并不是这样去做的。

现在摆在Vue面前的有两份虚拟DOM,一份是旧的,一份是新的。那么Vue这个时候就会去做一个事情,那就是虚拟DOM的对比算法。而对比的时候,就会依赖key。那具体是怎么对比的呢?我接下来再细说一下。

首先Vue会看第一个老六-40,它的key为0,然后他就会去旧DOM中找有没有key为0的,找到之后它就会去比较里面的内容,我们可以看到key为0的新DOM中是老六-40,而旧DOM中是张三-18,那么就发现两边的文本出现了不一致。然后再接着对比后面的input,我们可以看到两边的input是一样的。这个时候有的同学就会发出疑问,旧的DOM中如果残留着用户填写的信息的话,两边的虚拟DOM不就不一样了嘛?这里就需要我们注意一下,Vue这里比较的是在内存中的虚拟DOM,而input中填写的内容是在真实DOM中的。所以Vue这里针对input的对比结果就是两边的input是一样的。

说到这里重点就来了,那么针对比对出来的不一致的文本内容还有比较一致的input标签,Vue会做什么处理呢?

针对内容不一致的老六-40,Vue就会重新生成一个新的真实DOM,而针对被判定为一致的input标签,则继续沿用key为0,之前已经生成的真实DOM,就没必要再生成一次了,所以就会有以下情况。

所以以此类推,由于key使用了index,而且新加的节点被置于顶部,就导致所有节点的key都发生了变化,而input还是对应着之前的key,就导致input中有内容的时候,都发生了错位现象。

所以这里也就能解释为什么使用唯一标识p.id作为key的时候不会有这样的问题,因为不管位置怎么变化,Vue在使用比较算法的时候,key都是可以对应上的,而input,也不会发生错位的现象。

那为什么我们不写key的时候也会发生错位的现象呢?这是因为当我们不写key的时候,Vue就会默认使用index作为key,所以也会出现错位现象。

5.总结

面试题:react,Vue中的key有什么作用?(key的内部原理)

1.虚拟DOM中key的作用:

key是虚拟DOM对象的标识,当数据发生变化的时候,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

2.对比规则:

(1)旧虚拟DOM中找到了与新虚拟DOM相同的key:

如果虚拟DOM中的内容没变,则直接使用之前生成的真是DOM!

如果虚拟DOM中的内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

(2)旧虚拟DOM中未找到与新虚拟DOM相同的key

创建新的真实DOM,随后渲染到页面

3.用index作为key可能会引发的问题:

(1)若对数据进行逆序添加,逆序删除等破坏顺序的操作,则会产生没有必要的真实DOM更新,界面效果没问题,但是效率低

(2)如果结构中还包含输入类的DOM,则会产生错误DOM更新,界面会有问题

4.开发中如何选择key?

(1)最好使用每条数据的唯一标识作为key,比如id,手机号,身份证号,学号等唯一值

(2)如果不存在对数据的逆序添加,逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,则使用index作为key是没有问题的。

26.Vue列表渲染中key的作用与原理(内含虚拟DOM的对比算法详解)相关推荐

  1. vue列表渲染中key的作用_vue中:key的作用

    因为不理解 :key(v-bind:key),网上查了一些的资料,这篇写得非常不错,很简洁清楚. 其实不只是vue,react中在执行列表渲染时也会要求给每个组件添加上key这个属性. 要解释key的 ...

  2. vue列表渲染中key的作用_列表渲染和Vue的v-for指令

    Web渲染是Web开发中最常用的实战之一.动态列表渲染通常用于简洁友好的格式向用户渲染一系列相似的分组信息.在我们使用的每个Web应用程序中,都可以看到很多内容列表被用于Web应用程序当中. 在这篇文 ...

  3. vue 虚拟dom和diff算法详解

    虚拟dom是当前前端最流行的两个框架(vue和react)都用到的一种技术,都说他能帮助vue和react提升渲染性能,提升用户体验.那么今天我们来详细看看虚拟dom到底是个什么鬼 虚拟dom的定义与 ...

  4. 列表渲染 wx:key 的作用、条件渲染 wx:if 与 hidden 的区别

    这是微信小程序踩坑系列的第三篇,想要了解更多关于微信小程序开发的那些事,欢迎关注我的<微信小程序>专栏. 前言 开发微信小程序离不开"页面渲染",对于初学者来说很难理解 ...

  5. vue之购物车案例升级版、v-model之lazy、number、trim的使用、fetch和axios、计算属性、Mixins、虚拟dom与diff算法 key的作用及组件化开发

    文章目录 1.购物车案例升级版(含价格统计.全选/反选.商品增加减少) 2.v-model之lazy.number.trim的使用 3.fetch和axios 3.1.通过jquery+ajax实现v ...

  6. 5渲染判断_Vue页面渲染中key的应用实例教程

    引言 在前端项目开发过程中,el-table展示的结果列使用组件形式引入,其中某些字段通过:formatter方法转码,结果栏位的字段显示/隐藏控制也使用组件形式引入,前端在控制字段显示属性时,发现码 ...

  7. 【Vue】基础(三)条件渲染 - 列表渲染(key的作用与原理虚拟DOM解析) - 收集表单数据 - 持续更新中

    目录 11. 条件渲染 11.1 v-if 11.2 v-show 12. 列表渲染 12.1 v-for(基本列表使用) 12.2 key的作用与原理 真实DOM和其解析流程 虚拟 DOM 的好处 ...

  8. vue 相同的id不合并_vue中key的作用

    摘要 本文结合源码说明了key的作用,给出了一个不写key的反例,并分析了原因. 内容 key的作用 不写key会出的bug及原因分析 key的实践方案 key的作用 在数据变化前后,vue会得到两个 ...

  9. 【Vue】基础系列(五)列表渲染v-for | key的原理 | 数组 | 对象 | 删除替换 | 过滤与排序

    1. 列表显示 v-for指令 用于展示列表数据 语法:v-for="(item, index) in xxx" :key="yyy" 可遍历:数组.对象.字符 ...

最新文章

  1. python练习集100题(21-40)
  2. 无招胜有招之Java进阶JVM(七)对象模型
  3. 是学习Java还是Python?一张图告诉你!
  4. input层级高 小程序_获客、引流成本越来越高?开发小程序:低成本获客、引流...
  5. java 枚举与泛型_Java枚举和泛型
  6. ngnix有版本要求吗_新版本探秘:比赛/活动等其他系统的新增与优化~
  7. 2021软考软件设计师真题
  8. 最新PHP搞笑文字表情包在线制作网站源码
  9. 苹果android怎么设置,天猫魔盒怎么投屏使用 苹果和安卓手机操作设置方法
  10. 希腊字母 和 他的发音 Greek Alphabet and its Pronunciation
  11. xposed框架报错安装不上解决办法
  12. 【递归入门】组合的输出
  13. 脖子酸疼怎么办?初探解决方案
  14. 白鹭引擎 4.0 发布 让重度H5游戏研发更简单
  15. IEEE文献免费下载方法
  16. python : 新概念英语 课文转为html
  17. 解压chm后由hhc生成html索引页面
  18. 工件的安装与排序问题
  19. VHDL语言的数据类型
  20. 公有云托管K8s服务百花齐放,企业如何统一纳管、便捷管理?

热门文章

  1. mysql如何导出数据
  2. Shellcode生成工具Donut测试分析
  3. 静态ip和动态ip的区别能说明什么?怎么根据区别选择?
  4. 昨天写了一个小日历,日历显示一年的日历,暂时设定位2017年,分三个种代码...
  5. matlab7.01安装,win7系统安装matlab7.1的操作方法
  6. CentOS7中安装Tomcat8
  7. java 时间轮算法_时间轮算法解析(Netty HashedWheelTimer源码解读)
  8. GO语言reflect反射篇
  9. 转载大神神作之识狗君:Server端实现补充
  10. Google Payments?