vue基础知识十七:你知道vue中key的原理吗?说说你对它的理解

一、Key是什么
开始之前,我们先还原两个实际工作场景
1.当我们在使用v-for时,需要给单元加上key
<ul><li v-for="item in items" :key="item.id">...</li>
</ul>
2.用+new Date()生成的时间戳作为key,手动强制触发重新渲染
<Comp :key="+new Date()" />
那么这背后的逻辑是什么,key的作用又是什么?
一句话来讲
key是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,更准确, 更快的找到对应的vnode节点
场景背后的逻辑
当我们在使用v-for时,需要给单元加上key
- 如果不用key,Vue会采用就地复地原则:最小化element的移动,并且会尝试尽最大程度在同适当的地方对相同类型的element,做patch或者reuse。
- 如果使用了key,Vue会根据keys的顺序记录element,曾经拥有了key的element如果不再出现的话,会被直接remove或者destoryed
用+new Date()生成的时间戳作为key,手动强制触发重新渲染
- 当拥有新值的rerender作为key时,拥有了新key的Comp出现了,那么旧key Comp会被移除,新key Comp触发渲染
二、设置key与不设置key区别
举个例子:
创建一个实例,2秒后往items数组插入数据
<body><div id="demo"><p v-for="item in items" :key="item">{{item}}</p></div><script src="../../dist/vue.js"></script><script>// 创建实例const app = new Vue({el: '#demo',data: { items: ['a', 'b', 'c', 'd', 'e'] },mounted () {setTimeout(() => { this.items.splice(2, 0, 'f') // }, 2000);},});</script>
</body>
在不使用key的情况,vue会进行这样的操作:

分析下整体流程:
- 比较A,A,相同类型的节点,进行patch,但数据相同,不发生dom操作
- 比较B,B,相同类型的节点,进行patch,但数据相同,不发生dom操作
- 比较C,F,相同类型的节点,进行patch,数据不同,发生dom操作
- 比较D,C,相同类型的节点,进行patch,数据不同,发生dom操作
- 比较E,D,相同类型的节点,进行patch,数据不同,发生dom操作
- 循环结束,将E插入到DOM中
一共发生了3次更新,1次插入操作
在使用key的情况:vue会进行这样的操作:
- 比较A,A,相同类型的节点,进行patch,但数据相同,不发生dom操作
- 比较B,B,相同类型的节点,进行patch,但数据相同,不发生dom操作
- 比较C,F,不相同类型的节点
- 比较E、E,相同类型的节点,进行patch,但数据相同,不发生dom操作
- 比较D、D,相同类型的节点,进行patch,但数据相同,不发生dom操作
- 比较C、C,相同类型的节点,进行patch,但数据相同,不发生dom操作
- 循环结束,将F插入到C之前
一共发生了0次更新,1次插入操作
通过上面两个小例子,可见设置key能够大大减少对页面的DOM操作,提高了diff效率
设置key值一定能提高diff效率吗?
其实不然,文档中也明确表示
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出
建议尽可能在使用 v-for 时提供 key,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升
三、原理分析
源码位置:core/vdom/patch.js
这里判断是否为同一个key,首先判断的是key值是否相等如果没有设置key,那么key为undefined,这时候undefined是恒等于undefined
function sameVnode (a, b) {return (a.key === b.key && ((a.tag === b.tag &&a.isComment === b.isComment &&isDef(a.data) === isDef(b.data) &&sameInputType(a, b)) || (isTrue(a.isAsyncPlaceholder) &&a.asyncFactory === b.asyncFactory &&isUndef(b.asyncFactory.error))))
}
updateChildren方法中会对新旧vnode进行diff,然后将比对出的结果用来更新真实的DOM
function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {...while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {if (isUndef(oldStartVnode)) {...} else if (isUndef(oldEndVnode)) {...} else if (sameVnode(oldStartVnode, newStartVnode)) {...} else if (sameVnode(oldEndVnode, newEndVnode)) {...} else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right...} else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left...} else {if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)idxInOld = isDef(newStartVnode.key)? oldKeyToIdx[newStartVnode.key]: findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)if (isUndef(idxInOld)) { // New elementcreateElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)} else {vnodeToMove = oldCh[idxInOld]if (sameVnode(vnodeToMove, newStartVnode)) {patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)oldCh[idxInOld] = undefinedcanMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)} else {// same key but different element. treat as new elementcreateElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)}}newStartVnode = newCh[++newStartIdx]}}...
}
相关文章:
vue基础知识十七:你知道vue中key的原理吗?说说你对它的理解
一、Key是什么 开始之前,我们先还原两个实际工作场景 1.当我们在使用v-for时,需要给单元加上key <ul><li v-for"item in items" :key"item.id">...</li> </ul>2.用new Date()生成的时间戳作为key&#x…...
攻防演练蓝队|Windows应急响应入侵排查
文章目录 日志分析web日志windows系统日志 文件排查进程排查新增、隐藏账号排查启动项/服务/计划任务排查工具 日志分析 web日志 dirpro扫描目录,sqlmap扫描dvwa Python dirpro -u http://192.168.52.129 -b sqlmap -u "http://192.168.52.129/dvwa/vulnera…...
uniapp 小程序实现图片宽度100%、高度自适应的效果
因为image组件默认是有宽度跟高度的,所以这个高度不怎么好写 通过load事件来控制图片的高度 话不多说,直接上代码, <image class"img" src"/static/image.png" :style"{ height: imgHeight px }"mode&q…...
05. NXP官方SDK使用实验
05. NXP官方SDK使用实验 官方SDK移植 官方SDK移植 新建cc.h文件 SDK包里面会用到很多数据类型,所以需要在该文件中定义一些常用的数据类型 #pragma once #define __I volatile #define __O volatile #define __IO volatiletypedef sig…...
Python- JSON使用初探
JSON 在JSON格式中,{} 和 [] 是两种主要的数据结构,分别表示对象(或称为字典、哈希、map)和数组(或称为列表、序列)。 {} - 对象 在JSON中,对象是一组"key": value对的集合。这些键必…...
vim的配置文件
用户级别配置文件 ~/.vimrc 修改用户级别的配置文件只会影响当前用户, 不会影响其他的用户. 例如: 在用户的家目录下的.vimrc文件中添加 set tabstop4 ----设置缩进4个空格 set nu ----设置行号 set shiftwidth4 —设置ggG缩进4个空格, 默认是缩进8个空格 系统级别配置文件 /e…...
[python] pytest
在写一个项目前, 可以先编写测试模块 测试模块中包含了一个个最小的功能 当每一个功能都完善正确时 再将这些功能转换成项目运行的功能 多个项目运行的功能就组成了一个模块 多个模块就组成了一个项目服务 pytest 是一个 Python 测试框架,它提供了简单易用的语…...
【王道代码】【2.2顺序表】d1
关键字: 删除最小值最后位补齐;逆置;删除所有x;删除值为s到t区间的元素...
【Linux】【创建文件】Linux系统下在命令行中创建文件的方法
🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd🌐系列专栏:Linux技术&…...
Pytorch之MobileViT图像分类
文章目录 前言一、Transformer存在的问题二、MobileViT1.MobileViT网络结构🍓 Vision Transformer结构🍉MobileViT结构 2.MV2(MobileNet v2 block)3.MobileViT block🥇Local representations🥈Transformers as Convolutions (glob…...
03在命令行环境中创建Maven版的Java工程,了解pom.xml文件的结构,了解Java工程的目录结构并编写代码,执行Maven相关的构建命令
创建Maven版的Java工程 Maven工程的坐标 数学中使用x、y、z三个向量可以在空间中唯一的定位一个点, Maven中也可以使用groupId,artifactId,version三个向量在Maven的仓库中唯一的定位到一个jar包 groupId: 公司或组织域名的倒序, 通常也会加上项目名称代表公司或组织开发的一…...
论文阅读:CenterFormer: Center-based Transformer for 3D Object Detection
目录 概要 Motivation 整体架构流程 技术细节 Multi-scale Center Proposal Network Multi-scale Center Transformer Decoder Multi-frame CenterFormer 小结 论文地址:[2209.05588] CenterFormer: Center-based Transformer for 3D Object Detection (arx…...
Arduino驱动BNO055九轴绝对定向传感器(惯性测量传感器篇)
目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 BNO055是实现智能9轴绝对定向的新型传感器IC,它将整个传感器系统级封装在一起,集成了三轴14位加速度计,三轴16位陀螺仪,三轴地磁传感器和一个自带算法处理的32位微控制器。...
MQTT测试工具及使用教程
一步一步来:MQTT服务器搭建、MQTT客户端使用-CSDN博客 MQTT X 使用指南_mqttx使用教程-CSDN博客...
yolov7改进优化之蒸馏(一)
最近比较忙,有一段时间没更新了,最近yolov7用的比较多,总结一下。上一篇yolov5及yolov7实战之剪枝_CodingInCV的博客-CSDN博客 我们讲了通过剪枝来裁剪我们的模型,达到在精度损失不大的情况下,提高模型速度的目的。上一…...
视频美颜SDK,提升企业视频通话质量与形象
在今天的数字时代,视频通话已经成为企业与客户、员工之间不可或缺的沟通方式。然而,由于网络环境、设备性能等因素的影响,视频通话中的画面质量往往难以达到预期效果。为了提升视频通话的质量与形象,美摄美颜SDK应运而生ÿ…...
webmin远程命令执行漏洞
文章目录 漏洞编号:漏洞描述:影响版本:利用方法(利用案例):安装环境漏洞复现 附带文件:加固建议:参考信息:漏洞分类: Webmin 远程命令执行漏洞(CV…...
docker离线安装和使用
通过修改daemon配置文件/etc/docker/daemon.json来使用加速器sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": ["https://ullx9uta.mirror.aliyuncs.com"] } EOF sudo systemctl daemon-reload sudo syste…...
解决 MyBatis 一对多查询中,出现每组元素只有一个,总组数与元素数总数相等的问题
文章目录 问题简述场景描述问题描述问题原因解决办法 问题简述 笔者在使用 MyBatis 进行一对多查询的时候遇到一个奇怪的问题。对于笔者的一对多的查询结果,出现了这样的一个现象:原来每个组里有多个元素,查询目标是查询所查的组,…...
这应该是关于回归模型最全的总结了(附原理+代码)
本文将继续修炼回归模型算法,并总结了一些常用的除线性回归模型之外的模型,其中包括一些单模型及集成学习器。 保序回归、多项式回归、多输出回归、多输出K近邻回归、决策树回归、多输出决策树回归、AdaBoost回归、梯度提升决策树回归、人工神经网络、随…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
