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://www.mzph.cn/news/821765.shtml

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

相关文章

CTFHUB-技能树-Web前置技能-文件上传(前端验证—MIME绕过、00截断、00截断-双写后缀)

CTFHUB-技能树-Web前置技能-文件上传&#xff08;前端验证—MIME绕过、00截断、00截断-双写后缀&#xff09; 文章目录 CTFHUB-技能树-Web前置技能-文件上传&#xff08;前端验证—MIME绕过、00截断、00截断-双写后缀&#xff09;前端验证—MIME绕过有关MIMEMIME的作用 解题时有…

元宇宙VR虚拟线上展馆满足企业快速布展的需要

想要拥有一个VR线上虚拟展馆&#xff0c;展现您的城市风采或企业特色吗? 相比实体展馆搭建&#xff0c;VR线上虚拟展馆投入资金少&#xff0c;回报周期短&#xff0c;只需几个月的时间&#xff0c;您就能开始资金回笼。那么一个VR线上虚拟展馆多少钱呢? 深圳VR公司华锐视点基…

bp神经网络拟合函数未知参数【源码+视频教程】

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《复杂函数拟合案例分享》本专栏旨在提供 1.以案例的形式讲解各类复杂函数拟合的程序实现方法&#xff0c;并提供所有案例完整源码&#xff1b;2.…

无人零售行业展望:智能化与便利性引领未来

无人零售行业展望&#xff1a;智能化与便利性引领未来 无人零售&#xff0c;这一依靠智能化技术如人工智能、物联网、和大数据的零售模式&#xff0c;正逐步成为全球零售行业的新趋势。该模式允许消费者在没有店员的情况下自助完成购物&#xff0c;提供了24小时服务&#xff0…

IO、存储、硬盘、文件系统相关常识

目录 IO 文件系统 文件在硬盘上的存储 IO IO&#xff0c;就是Input和Output&#xff0c;即输入和输出操作。我们的电脑可以通过网络下载文件&#xff0c;也可以通过网络上传文件。通过网络下载文件就是输入操作&#xff0c;上传文件就是输出。如何区分输入和输出呢&#xf…

负载均衡的原理及算法简介

负载均衡&#xff08;Load Balancing&#xff09;是一种用于在多台服务器之间分配网络流量的技术&#xff0c;旨在优化系统资源利用率、提高服务可用性、增强系统的伸缩性和容错能力。其基本原理是将来自客户端的请求分散到一个服务器集群中的各个服务器上&#xff0c;而不是让…

postgresql|数据库|实时数据库监控利器 pg_activity 的部署和初步使用

前言&#xff1a; postgresql的调优是比较重要的&#xff0c;那么&#xff0c;如何调优呢&#xff1f;自然是在某一个时间段内&#xff0c;通常是业务高峰期或者压测时间内实时观察数据库的运行情况&#xff0c;然后通过观察到的信息判断数据库的瓶颈&#xff0c;比如&#xf…

通过adb 命令打印安装在第三方模拟器上的log

1&#xff0c;环境&#xff1a;Windows 11 &#xff0c;第三方模拟器 网易的MuMu 步骤&#xff1a; 1&#xff0c;打开cmd&#xff0c;输入 adb connect 172.0.0.1:7555 2&#xff0c;在cmd&#xff0c;再次输入adb logcat 回车

简单了解 HTTP 基础知识

HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;是用于在网络上传输数据的一种协议&#xff0c;对于网络开发人员来说&#xff0c;理解这一协议是至关重要的。由于其广泛的应用&#xff0c;除了在网页应用传输数据之外&#xff0c;它还被应…

算法学习——LeetCode力扣补充篇8(146. LRU 缓存、 215. 数组中的第K个最大元素、25. K 个一组翻转链表)

算法学习——LeetCode力扣补充篇8 146. LRU 缓存 146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09; 描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化…

weblogic JSP action的配置

action(如xxx.do&#xff09;可以在Java文件中通过注解的方式配置&#xff0c;也可以在web.xml中进行配置 在java文件中配置的场合 WebServlet(xxxx.do) 并实现支持的方法&#xff1a;doGet或doPost等 或者 WebServlet(xxxx.do) 并实现service方法 所有method的处理方法都会…

华为 2024 届实习招聘——硬件-电源机试题(四套)

华为 2024 届实习招聘——硬件-电源机试题&#xff08;四套&#xff09; 部分题目分享&#xff0c;完整版带答案(有答案&#xff0c;答案非官方&#xff0c;未仔细校正&#xff0c;仅供参考&#xff09;&#xff08;共四套&#xff09; 获取&#xff08;WX:didadidadidida313&…

【保姆级讲解docker 的常用命令】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

设计模式-命令模式(Command)

1. 概念 命令模式&#xff08;Command Pattern&#xff09;是一种行为型设计模式&#xff0c;也被称为动作模式或事务模式。它的核心思想是将一个请求封装成一个对象&#xff0c;从而使你可以用不同的请求对客户进行参数化。对请求排队或记录&#xff0c;以及支持可撤销的操作…

Excel高效办公:人力资源管理(AI版)

AI人力资源管理一本通&#xff1a;147个“温馨提示”53个“教您一招”&#xff0c;掌握使用Excel高效完成人力资源管理工作的“心法”&#xff0c;助你早做完、不加班。 一本书掌握人力资源高效管理的“心法”&#xff01; 案例丰富&#xff0c;参考性强&#xff1a;本书不是…

Web3与社会契约:去中心化治理的新模式

在数字化时代&#xff0c;技术不断为我们提供新的可能性&#xff0c;而Web3技术作为一种基于区块链的创新&#xff0c;正在引领着互联网的下一波变革。它不仅改变了我们的经济模式和商业逻辑&#xff0c;还对社会契约和权力结构提出了全新的挑战和思考。本文将深入探讨Web3的基…

excel 无法正确处理 1900-03-01 前的日期

问题由来&#xff1a;excel 用公式 TEXT(A1,"yyyy-mm-dd") 转日期时&#xff0c;当A1 的值等于59 的时候&#xff0c;返回值是1900-02-28&#xff1b;当A1 的值等于61 的时候&#xff0c;返回值是1900-03-01&#xff1b;那么当 A1的值为 60 的时候&#xff0c;返回值…

【iOS】——SDWebImage源码学习

文章目录 一、SDWebIamge简介二、SDWebImage的调用流程SDWebImage源码分析1.UIImageViewWebCache层2.UIViewWebCache层3.SDWebManager层4.SDWebCache层5.SDWebImageDownloader层 一、SDWebIamge简介 SDWebImage是iOS中提供图片加载的第三方库&#xff0c;可以给UIKit框架中的控…

C语言【数组】

一、数组基本语法 1. 什么是数组 数组是c语言的一种数据结构&#xff0c;用于存储一组具有相同数据类型的数据&#xff1b; 数组中每个元素可以通过下标进行访问&#xff0c;索引从0开始&#xff0c;最大值为数组长度-1。 2. 数组的使用 类型 数组名[元素个数]; int arr[5]…

ICV:《中美量子产业融资比较分析》

近日&#xff0c;全球前沿科技咨询公司ICV发布了A Comparative Analysis of Quantum Industry Financing in the U.S and China&#xff08;美国和中国量子产业融资比较分析&#xff09;报告。该报告旨在对中美两国在量子技术领域的投融资情况进行比较分析&#xff0c;探讨其差…