Vue 3 Diff 算法受 `v-for` 循环中的 `key` 属性影响
Vue 3 的 Diff 算法会受到 v-for 循环中的 key 属性的影响,key 的选择直接关系到 Diff 算法的效率和最终的 DOM 更新结果。
key 的作用
在 Vue 中,key 是一种标识,它用于唯一标记每个虚拟 DOM 节点。Diff 算法会根据 key 判断新旧节点是否是同一个节点。
没有 key 时
- 如果没有
key,Vue 会默认使用节点的索引值作为标识。 - 当列表发生变化时,由于索引可能对应了错误的节点,会导致无法正确复用现有节点,从而增加不必要的 DOM 操作。
有 key 时
- 当指定了唯一的
key,Vue 可以准确匹配新旧节点。 - 这样可以复用相同
key的节点,避免误匹配或冗余操作,提高性能。
Diff 算法如何处理 key
-
key匹配规则- 在 Diff 过程中,如果新旧节点的
key相同,Vue 会认为它们是相同的节点,执行更新操作而非重建。 - 如果
key不同,Vue 会移除旧节点并创建新节点。
- 在 Diff 过程中,如果新旧节点的
-
有
key的场景- Vue 通过
key快速定位新旧节点在列表中的位置,避免盲目比较,从而优化性能。 - Vue 3 使用 最长递增子序列(LIS) 算法来减少 DOM 操作,
key的稳定性是实现该优化的重要前提。
- Vue 通过
-
没有
key的场景- Vue 会退化为按索引逐一比较的模式。
- 如果数据顺序发生变化,可能会导致大量的节点重建和移动。
案例分析
示例 1:没有 key 的情况
<template><div><div v-for="item in items">{{ item }}</div></div>
</template><script>
export default {data() {return {items: [1, 2, 3]};},mounted() {setTimeout(() => {this.items = [3, 2, 1]; // 改变顺序}, 1000);}
};
</script>
结果:
- Vue 会将
[1, 2, 3]和[3, 2, 1]按索引逐个对比。 - 由于没有
key,节点内容不同,导致所有节点被替换,性能较差。
示例 2:使用唯一的 key
<template><div><div v-for="item in items" :key="item">{{ item }}</div></div>
</template><script>
export default {data() {return {items: [1, 2, 3]};},mounted() {setTimeout(() => {this.items = [3, 2, 1]; // 改变顺序}, 1000);}
};
</script>
结果:
- Vue 根据
key匹配节点[1, 2, 3]和[3, 2, 1],只移动节点位置,而不会销毁重建。 - 这样可以显著减少 DOM 操作,提高性能。
key 影响 Diff 的性能与结果
-
性能影响
- 没有
key:Vue 需要逐个比对每个节点的内容,无法充分复用节点。 - 有
key:Vue 可以快速确定哪些节点需要更新、移动或删除,从而减少不必要的 DOM 操作。
- 没有
-
更新结果的准确性
- 没有
key:可能会导致节点错误复用,渲染结果不符合预期。 - 有
key:可以确保每个节点的复用和更新都是正确的。
- 没有
<template><div class="ForKeyInDiffVNode"><el-button @click="change">改变值</el-button><div class="item-class" v-for="(item, idx) in lists" :key="idx"><el-checkbox></el-checkbox><span>{{ item.name }}</span></div></div>
</template><script setup lang="ts">
import {ref} from "vue";const lists = ref([{name: 'hmk',age: 20,show: false},{name: '张三',age: 21,show: false},{name: '李四',age: 22,show: false},{name: '王五',age: 23,show: false}
])
// 之前选中第三个,点击删除第三个之前的数据后,会出现错乱情况
// 给key加上一个唯一的id即可解决问题
const change = () => {lists.value.splice(1, 1)
}</script>
最佳实践:key 的选择
-
使用唯一标识符
- 使用数据中的唯一标识(如 ID)作为
key:<div v-for="item in items" :key="item.id">{{ item.name }}</div> - 避免使用非唯一的值(如索引)作为
key,因为数据顺序变化时可能会导致错误复用。
- 使用数据中的唯一标识(如 ID)作为
-
避免使用索引作为
key- 索引是动态的,当列表顺序改变或元素插入时,索引会变化,导致 Diff 结果不准确:
<div v-for="item in items" :key="index">{{ item }}</div> - 如果数据内容变化频繁,索引
key会导致不必要的 DOM 重建。
- 索引是动态的,当列表顺序改变或元素插入时,索引会变化,导致 Diff 结果不准确:
-
保证
key的稳定性key应该在组件的整个生命周期内保持不变,否则会导致 Diff 结果错误。
总结
-
key对 Diff 算法至关重要:- 没有
key:Vue 会按索引匹配,导致错误复用和性能下降。 - 有
key:Vue 可高效、准确地更新节点,减少 DOM 操作。
- 没有
-
选择唯一且稳定的
key:- 推荐使用数据中的唯一标识符(如
id)。 - 避免使用索引或动态值作为
key。
- 推荐使用数据中的唯一标识符(如
-
Diff 性能优化:
- Vue 3 使用
key时可以充分利用最长递增子序列(LIS)优化算法,最小化 DOM 移动和更新操作,提高性能。
- Vue 3 使用
相关文章:
Vue 3 Diff 算法受 `v-for` 循环中的 `key` 属性影响
Vue 3 的 Diff 算法会受到 v-for 循环中的 key 属性的影响,key 的选择直接关系到 Diff 算法的效率和最终的 DOM 更新结果。 key 的作用 在 Vue 中,key 是一种标识,它用于唯一标记每个虚拟 DOM 节点。Diff 算法会根据 key 判断新旧节点是否是…...
江科大STM32入门——看门狗笔记整理
wx:嵌入式工程师成长日记 (一)简介 WDG(Watchdog)看门狗看门狗可以监控程序的运行状态,当程序因为设计漏洞(无法预料)、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及…...
【计算机网络】lab7 TCP协议
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀计算机网络_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 实验目的…...
计算机视觉:解锁未来智能世界的钥匙
计算机视觉:解锁未来智能世界的钥匙 在信息技术飞速发展的今天,计算机视觉作为人工智能领域的一个重要分支,正以前所未有的速度改变着我们的生活与工作方式。它使机器能够“看”并理解图像和视频中的信息,为自动驾驶、医疗影像分…...
Java的Stream流和Option类
1. Stream 流 背景 Stream是Java 8引入的一个用于处理集合(或其他数据源)中的元素的API。它提供了一种声明式的方式来处理数据,并可以链式调用。Stream支持惰性求值,也支持并行流处理。 1.1 创建 Stream 创建一个Stream可以通…...
深入理解ASP.NET Core 管道的工作原理
在 .NET Core 中,管道(Pipeline)是处理 HTTP 请求和响应的中间件组件的有序集合。每个中间件组件都可以对请求进行处理,并将其传递给下一个中间件组件,直到请求到达最终的处理程序。管道的概念类似于流水线,…...
多模态论文笔记——CLIP
大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍这几年AIGC火爆的隐藏功臣,多模态模型:CLIP。 文章目录 CLIP(Contrastive Language-Image Pre-training)…...
brpc之baidu_protocol
简介 是brpc默认使用的协议 初始化 Protocol baidu_protocol { ParseRpcMessage,SerializeRequestDefault, PackRpcRequest,ProcessRpcRequest, ProcessRpcResponse,VerifyRpcRequest, NULL, NULL,CONNECTION_TYPE_ALL, "baidu_std" };协议定义 定义在baidu_rpc…...
LeetCode:39. 组合总和
跟着carl学算法,本系列博客仅做个人记录,建议大家都去看carl本人的博客,写的真的很好的! 代码随想录 LeetCode:39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 cand…...
SOLID原则学习,开闭原则(Open Closed Principle, OCP)
文章目录 1. 定义2. 开闭原则的详细解释3. 实现开闭原则的方法4. 总结 1. 定义 开闭原则(Open-Closed Principle,OCP)是面向对象设计中的五大原则(SOLID)之一,由Bertrand Meyer提出。开闭原则的核心思想是…...
Unreal Engine 5 C++ Advanced Action RPG 七章笔记
第七章 Ranged Enemy 2-Ranged Enemy Starting Weapon 制作新敌人的流程准备 新敌人的武器起始的状态数据自己的战斗能力投射能力自己的行为树 创建角色,添加武器,添加数据,就是继承之前的基类敌人的 运行结果 3-Glacer Starting Stats 看看就行,就是复制曲线表格更改数…...
自动连接校园网wifi脚本实践(自动网页认证)
目录 起因执行步骤分析校园网登录逻辑如何判断当前是否处于未登录状态? 书写代码打包设置开机自动启动 起因 我们一般通过远程控制的方式访问实验室电脑,但是最近实验室老是断电,但重启后也不会自动连接校园网账户认证,远程工具&…...
HTTP/HTTPS ⑤-CA证书 || 中间人攻击 || SSL/TLS
这里是Themberfue ✨上节课我们聊到了对称加密和非对称加密,实际上,单纯地非对称加密并不能保证数据不被窃取,我们还需要一个更加重要的东西——证书 中间人攻击 通过非对称加密生成私钥priKey和公钥pubKey用来加密对称加密生成的密钥&…...
traceroute原理探究
文章中有截图,看不清的话,可以把浏览器显示比例放大到200%后观看。 linux下traceroute的原理 本文通过抓包观察一下linux下traceroute的原理 环境:一台嵌入式linux设备,内网ip是192.168.186.195,其上有192.168.202.…...
50_Lua垃圾回收
1.Lua垃圾回收机制概述 Lua采用了一种自动内存管理机制,称为垃圾回收(Garbage Collection, GC)。垃圾回收的主要目的是回收程序中不再被使用的内存,从而避免内存泄漏。Lua的垃圾回收器负责回收动态分配的对象,如函数、用户数据、表、字符串、线程、内部结构等。Lua的垃圾…...
Git-2-:Cherry-Pick 的使用场景及使用流程
前面我们说了 Git合并、解决冲突、强行回退等解决方案 >> 点击查看 这里再说一下 Cherry-Pick功能,Cherry-Pick不是merge,只是把部分功能代码Cherry-Pick到远程的目标分支 git cherry-pick功能简介: git cherry-pick 是用来从一个分…...
【C++】21.map和set的使用
文章目录 1. 序列式容器和关联式容器2. set系列的使用2.1 set和multiset参考文档2.2 set类的介绍2.3 set的构造和迭代器构造函数:双向迭代器迭代器: 2.4 set的增删查2.5 insert和迭代器遍历使用样例:2.6 find和erase使用样例:2.7 …...
burpsiute的基础使用(2)
爆破模块(intruder): csrf请求伪造访问(模拟攻击): 方法一: 通过burp将修改,删除等行为的数据包压缩成一个可访问链接,通过本地浏览器访问(该浏览器用户处于登陆状态&a…...
ElasticSearch 同义词匹配
synonym.txt 电脑, 计算机, 主机 复印纸, 打印纸, A4纸, 纸, A3 平板电脑, Pad DELETE /es_sku_index_20_20250109 PUT /es_sku_index_20_20250109 {"settings": {"index": {"number_of_shards": "5","number_of_replicas&quo…...
linux RT-Preempt spin lock实现
一、spin_lock概述 Spinlock是linux内核中常用的一种互斥锁机制,和mutex不同,当无法持锁进入临界区的时候,当前执行线索不会阻塞,而是不断的自旋等待该锁释放。正因为如此,自旋锁也是可以用在中断上下文的。也正是因为…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
