vue的就地更新与v-for的key属性

vue的就地更新

Vue中的就地更新到底是怎么回事,为什么会存在就地更新的现象?

注意下面的例子,使用v-for指令时,没有绑定key值,才有就地更新的现象,因为Vue默认按照就地更新的策略来更新v-for渲染的元素列表

下面的例子很简单,就是循环遍历数据list,当li标签被点击的时候就进行删除操作。现在我们关心的并不是如何实现功能,而是点击删除按钮时,整个ElementsDOM结构树是如何变化的。
按照常理来说,如果我们点击第一个li标签的删除按钮,那么就应该删除第一个li标签,点击第二个删除按钮,就删除第二个li标签,依次类推。但实际上Vue并不是这样做的,那Vue是怎么做的呢?
比如说,我现在点击第二个li标签的删除按钮,第二个li标签的内容是item-2。实际上Vue是先将第三个li标签的内容item-3,移动到item-2<span></span>标签内部,然后再删除内容是item-3li标签。换句话说,就是点击第二个删除按钮,删除的并不是第二个li标签,其实删除的是第三个li标签,Vue只是将第三个li标签中<span></span>标签的内容item-3,移动到第二个li标签中的<span></span>标签内部。

const App = {data() {return {list: [{id: 1,value: 'item-1'},{id: 2,value: 'item-2'},{id: 3,value: 'item-3'}]}},template:`<ul><li v-for="(item, index) of list"><span>{{ item.value }}</span><button  @click="handleClickDel(index)">Delete</button></li></ul>`,methods: {handleClickDel(index) {this.list.splice(index,1);}}
}

没有点击item-2时的dom结构

image.png

点击item-2的delete按钮时,dom树的变化

点击item-2Delete按钮时,我们发现DOM结构树发生了更改。注意Elements背景色是紫色的标签,背景是紫色说明标签内容发生了变化。那么我们之前说,Vue此时删除的并不是第二个li标签,只是将item-3字符串移动到第二个li标签中的<span></span>标签中,删除第三个li标签。所以我们从图中可以看到,第二个li标签内容发生变化,而第三个li标签被删除。这种现象就称为就地更新。
image.png

就地更新的优势

上面叙述了就地更新的现象,那为什么Vue中存在就地更新的现象呢?它的优势又是什么呢?我们再来看一个例子吧。
我们首先看模板template中的两个<div></div>标签有什么共同点呢?两个<div></div>标签中都拥有标签<a href="#"></a>,按照常理来说,如果变量isLogin返回的是Truthy(真值)的时候,那么第一个<div></div>标签内部的span、a标签都会被渲染;当isLogin返回的是Falsy(虚值)的时候,那么第二个<div></div>标签内部的两个a标签也都会被渲染。
但是实际上并不是这样滴,Vue拥有就地更新的现象。所以点击<a href="javascript:;" @click="isLogin = true">登录</a>的时候,Vue会将<a href="#">注册</a>标签内部的字符串注册文字改为xiaoming,对这个<a href="#"></a>标签进行复用🤔,而不是重新渲染一个新的DOM元素。
我们通过这个例子就能看出Vue中就地更新的优势,首先就地更新是非常高效的,能够复用其它的DOM元素,减少DOM操作,减少DOM元素的重绘与回流,减少浏览器的性能消耗。

const App = {data() {return {isLogin: false}},template:`<divv-if="isLogin"><span>欢迎您~</span><a href="#"> xiaoming </a></div>  <div v-else><a href="javascript:;" @click="isLogin = true">登录</a><a href="#">注册</a></div>`
}

就地更新的问题

默认模式是高效的,但是只适用于列表渲染输出的结果不依赖子组件或者临时的DOM状态(例如表单输入值)的情况。
我们如何理解“**只适用于列表渲染输出的结果不依赖子组件或者临时的DOM状态(例如表单输入值)的情况”**这句话呢?我们来通过下面的例子进行解释。

就地更新遇到临时的dom状态

下面的例子中,(图1)是DOM结构树初始化的状态。当我手动往input框输入值后,点击item-2Detele按钮,此时会出现(图2)的状态,我们发现Vue的的确确是按照就地更新的策略进行的渲染列表。但是我们输入框输入的值并没有进行更新。是因为我手动输入值的状态是临时DOM状态,Vue没有办法判断节点内部这个临时DOM状态有什么用,因此Vue并不去会跟踪这个状态。所以就地更新遇见临时DOM状态就会出现(图2)中的问题。

const App = {el:'#app',data () {return {list: [{id: 1,value: 'item-1'},{id: 2,value: 'item-2'},{id: 3,value: 'item-3'}]}},template:`<ul><li v-for="(item, index) of list" :key="item.id"><span> {{ item.value }} </span><input type="text" /><button @click="deleteItem(index)">DELETE</button></li></ul>`,methods: {deleteItem(index) {this.list.splice(index,1);} }
}

(图1)
image.png
(图2)
image.png
当然上面例子相当于这样的写法,此时tempArr变量是固定的,是不变化的;因为tempArr是不变化的,那么input标签内部绑定的value值是没有办法更新的,而碰上Vue当中的就地更新的策略就出现(图2)中同样的问题。

const App = {data() {return {tempArr: [1, 2, 3],list:[{id: 1,value: 'item-1'},{id: 2,value: 'item-2'},{id: 3,value: 'item-3'}]}},template: `<div><ul><li v-for="(item,index) of list"><span> {{ item.value }} </span><input type="text" :value="tempArr[index]" /><button @click="deleteItem(index)">DELETE</button></li></ul></div>`,methods: {deleteItem(index) {this.list.splice(index, 1);}}
}
就地更新遇到子组件

Vue文档中指出就地更新**只适用于列表渲染输出的结果不依赖子组件,**也就是说你模板中列表渲染的结果不依赖子组件的时候就地更新策略不会出现问题。但是如果你模板中列表渲染的结果依赖子组件的时候,就地更新策略就会出现问题。因为子组件内部可能会有复杂的逻辑,所以Vue监控不了子组件内部的数据。
例如下面中的例子,列表渲染输出的结果依赖子组件MyComponent(需要子组件MyComponent),然后Vue中v-for指令默认按照就地更新策略进行渲染,所以出现(图3)中出现的问题。

const MyComponent = {props: {num: Number,},template: `<span> {{ num }} </span>`
}
const App = {components: {MyComponent},data() {return {list: [{id: 1,value: 'item-1'},{id: 2,value: 'item-2'},{id: 3,value: 'item-3'}],tempArr:[1, 2, 3]}},template: `<div><ul><li v-for="(item, index) of list"><span> {{ item.value }} - </span><my-component :num="tempArr[index]"></my-component><input type="text" :value="tempArr[index]" /><button @click="deleteItem(index)">DELETE</button></li></ul></div>`,methods: {deleteItem(index) {this.list.splice(index, 1);}}
};

(图3)
image.png

解决就地更新遇到的问题

解决Vue中就地更新的方法就是给循环的每一个标签绑定一个唯一的key值,并且key值不能够变更。添加key值之后就没有就地更新的现象出现了,因为添加唯一key值后,Vue后面的驱动能够追踪绑定的元素。
下面的例子中我们在v-for指令下绑定唯一的key值为item.id,此时按照常理来说已经可以解决就地更新遇见的问题,但是发现还是没有效果,v-for指令渲染列表时依旧使用的是就地更新的策略。这又是为什么呢?
原因在于<my-component :num="tempArr[index]" /><input type="text" :value="tempArr[index]" />标签中,tempArr[index]属性的index属性来源于v-for指令,因为这个index值会随着绑定的数据list长度的变化而变化,所以导致绑定的元素无法对应上,所以还是会执行就地更新的策略。
这也是为什么不推荐v-for指令中,绑定key值不要绑定index的原因,因为你的增加、删除操作会导致index值的变化,而如果绑定的key值在渲染之后还会不断的变化,那么导致在Vue底层中判断新老节点的结果一致(底层源码中通过a.key ===b.key判断key值),如果结果一致的话,就执行就地更新的策略。如果绑定的key值是静态的,那么新节点绑定的key值于老节点绑定的key值肯定不同,如果底层判断新老节点的结果不一致的话,会进行打补丁patch的其它逻辑判断,不会执行就地更新的逻辑,就能够追踪每一个绑定的节点。

const MyComponent = {props: {num: Number,},template: `<span> {{ num }} </span>`
}
const App = {components: {MyComponent},data() {return {list: [{id: 1,value: 'item-1'},{id: 2,value: 'item-2'},{id: 3,value: 'item-3'}],tempArr:[1, 2, 3]}},template: `<div><ul><li v-for="(item, index) of list":key="item.id"><span> {{ item.value }} - </span><my-component :num="tempArr[index]"></my-component><input type="text" :value="tempArr[index]" /><button @click="deleteItem(index)">DELETE</button></li></ul></div>`,methods: {deleteItem(index) {this.list.splice(index, 1);}}
};

通过上述的逻辑,我们修改模板template的代码,将绑定过动态index值的地方都换成静态的属性item.id。按照分析,v-for指令渲染列表时候就不会执行就地更新的策略,Vue也就能够追踪绑定的元素。从(图4)也可以看出的的确确没有执行就地更新的策略。

 template: `<div><ul><li v-for="(item, index) of list":key="item.id"><span> {{ item.value }} - </span><my-component :num="item.id"></my-component><input type="text" :value="item.id" /><button @click="deleteItem(index)">DELETE</button></li></ul></div>`,

(图4)
image.png

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

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

相关文章

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于用户生产场景辨识的电压暂降经济损失评估》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

十大远程控制软件排名

远程控制软件在现代计算环境中扮演着至关重要的角色&#xff0c;它们使得用户能够轻松地访问和管理远程计算机或设备。随着技术的不断进步&#xff0c;市场上涌现出许多优秀的远程控制工具。以下是对当前市场上十大远程控制软件的简要排名和介绍&#xff0c;以帮助您选择最适合…

Go Plugin:动态模块的加载与问题解析_go语言加载动态库的工具(1)

先自我介绍一下&#xff0c;小编浙江大学毕业&#xff0c;去过华为、字节跳动等大厂&#xff0c;目前阿里P7 深知大多数程序员&#xff0c;想要提升技能&#xff0c;往往是自己摸索成长&#xff0c;但自己不成体系的自学效果低效又漫长&#xff0c;而且极易碰到天花板技术停滞…

Linux环境如何端口映射?

在网络通信中&#xff0c;端口映射是一项重要的技术&#xff0c;在Linux系统中广泛应用。它的主要作用是实现不同网络设备之间的通信&#xff0c;使得远程访问成为可能。本文将介绍Linux端口映射的基本原理和应用场景&#xff0c;并重点介绍了一种名为【天联】的组网优势。 端口…

第47期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

操作系统—GCC与编译全流程

文章目录 GCC与编译全流程1.GCC是什么&#xff1f;2.编译全流程(1).GCC到底做了哪些事情&#xff1f;(2).预处理I.预处理会做什么II.预处理器主要包含什么&#xff1f;III.宏的一些魔法 (3).编译I.基本流程II.编译优化III.一点例子 (4).汇编(5).链接(6).说到这里&#xff0c;为…

AIGC实战——VQ-GAN(Vector Quantized Generative Adversarial Network)

AIGC实战——VQ-GAN 0. 前言1. VQ-GAN2. ViT VQ-GAN小结系列链接 0. 前言 本节中&#xff0c;我们将介绍 VQ-GAN (Vector Quantized Generative Adversarial Network) 和 ViT VQ-GAN&#xff0c;它们融合了变分自编码器 (Variational Autoencoder, VAE)、Transformer 和生成对…

免费的 ChatGPT、GPTs、AI绘画(国内版)

&#x1f525;博客主页&#xff1a;白云如幻❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ ChatGPT3.5、GPT4.0、GPTs、AI绘画相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚…

Oracle 正则,开窗,行列转换

1.开窗函数 基本上在查询结果上添加窗口列 1.1 聚合函数开窗 基本格式: ..... 函数() over([partition by 分组列,...][order by 排序列 desc|asc][定位框架]) 1&#xff0c;partition by 字段 相当于group by 字段 起到分组作用2&#xff0c;order by 字段 即根据某个字段…

客诉技术架构:构建客户满意的数字化支持系统

随着数字化时代的到来&#xff0c;客户体验已经成为企业竞争的关键因素之一。而客诉技术架构作为支持客户服务和解决问题的关键系统&#xff0c;对于企业提升客户满意度和品牌声誉具有重要意义。本文将深入探讨客诉技术架构的重要性、关键要素以及如何构建一个有效的客户支持系…

女上司问我:误删除PG百万条数据,可以闪回吗?

作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验 擅长主流数据Oracle、MySQL、PG、openGauss运维 备份恢复&#xff0c;安装迁移&#xff0c;性能优化、故障应急处理等可提供技术业务&#xff1a; 1.DB故障处理/疑难杂症远程支援 2.Mysql/PG/Oracl…

vagrant 安装虚拟机,docker, k8s

第一步&#xff1a;安装虚拟机 1、安装 vagrant 本机是 mac, 但是这一步不影响&#xff0c;找对应操作系统的安装方式就行了。 vagrant 下载地址 brew install vagrant 2、下载 VirtualBox 虚拟机 VirtualBox 下载地址 找到对应系统下载&#xff0c;安装就可以。 尽量把…

【Rust日报】2024-04-15 拯救地球,请使用Rust编程

拯救地球&#xff0c;请使用Rust编程 本文讨论了如何通过在Rust编程语言中编码&#xff0c;可以更有效地利用现有资源以帮助保护我们的星球。 通过在实际项目中将PHP应用重写为Rust&#xff0c;作者体验到了Rust不仅在维护性、开发效率和错误减少方面有优势&#xff0c;还在性能…

「51媒体」媒体邀约新闻稿件发布应该如何筛选媒体?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 在媒体邀约新闻稿件发布的过程中&#xff0c;筛选媒体是一个至关重要的环节。我们需要考虑以下因素&#xff1a; 目标受众匹配度&#xff1a;首先&#xff0c;需要明确新闻稿件的目标受众…

汉字编码实验

Logisim的简介和安装 首先要知道什么是logisim? Logisim是一种用于数字电路设计和模拟的开源工具&#xff0c;Logisim在2014年10月11日无限期暂停。因它足够简单&#xff0c;可以帮助学习逻辑电路相关的基本概念而闻名。Logisim被世界各地大学的学生在课程中使用。 Logisim的…

屏幕录制软件Bandicam

一、软件特点 1. 屏幕录制功能Bandicam可以录制各种屏幕活动&#xff0c;包括软件操作、网络教学、在线视频等。它支持高清录制&#xff0c;确保录制内容的质量较高而文件大小相对较小。 2. 游戏录制能力该软件特别适用于游戏录制&#xff0c;支持2D和3D游戏视频的录制&#x…

【AIGC】AIGC在虚拟数字人中的应用:塑造未来互动体验的革新力量

&#x1f680; &#x1f680; &#x1f680;随着科技的快速发展&#xff0c;AIGC已经成为引领未来的重要力量。其中&#xff0c;AIGC在虚拟数字人领域的应用更是引起了广泛关注。虚拟数字人作为一种先进的数字化表达形式&#xff0c;结合了3D建模、动画技术、人工智能等多种先进…

Python-VBA函数之旅-eval函数

目录 一、eval函数的常见应用场景&#xff1a; 二、eval函数安全使用注意事项&#xff1a; 三、eval函数与exec函数对比分析&#xff1a; 1、eval函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、相关文章&#xff1a; 个人主页&#xff1a;ht…

【论文阅读02】一种基于双通道的水下图像增强卷积神经网络

来源&#xff1a;海洋论坛▏一种基于双通道的水下图像增强卷积神经网络 当前不会的 一、背景&#xff1a; 水下图像增强方法包含有无水下成像模型的水下图像增强方法、基于水下成像模型的水下图像恢复方法、水下成像模型与深度学习相结合的方法以及完全采用深度学习的方…

大数据平台搭建2024(二)

二&#xff1a;Hive安装 只在node01上操作 1 安装MySQL 8.0 最小化安装需要安装这个 yum install -y wget1-1 下载MySQL的yum源 wget http://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm检查是否安装成功 rpm -qpl mysql80-community-release-el7-7.n…