vue2-diff算法

1、diff算法是什么?
diff算法是一种通过同层的树节点进行比较的高效算法。
其有两个特点:
比较只会在同层级进行,不会跨层级进行。
在diff比较的过程中,循环从两边向中间比较。
diff算法在很多场景中都有应用,在vue中,作用于虚拟Dom渲染成真实dom的新旧Vnode节点比较

2、比较方式
diff整体策略为:深度优先,同层比较
1)比较只会在同层级进行,不会跨层级比较
在这里插入图片描述

2)比较的过程中,循环从两边向中间收拢。
在这里插入图片描述
下面举一个vue通过diff算法更新的例子。
新旧vnode节点如下图所示:
在这里插入图片描述
第一次循环后,发现旧节点D与新节点D相同,直接复用旧节点D作为diff后的第一个真实节点,同时旧节点endIndex移动到C,新节点的startIndex移动到C。在这里插入图片描述
第二次循环后,同样是旧节点的末尾和新节点的开头相同(节点C),同理,diff后创建了C的真实节点插入到第一次创建的D节点后面,同时旧节点的endIndex移动到了B,新节点的startIndex移动到了E。
在这里插入图片描述
第三次循环中,发现E没有找到,这时候只能直接创建新的真实节点E,插入到第二次创建的C节点之后。同时新节点的startIndex移动到了A,旧节点的startIndex和endIndex都保持不动。
在这里插入图片描述
第四次循环中,发现了新旧节点的开头相同(都是A),于是diff后创建了A的真实节点,插入到前一次创建的E节点后面。同时旧节点的startIndex移动到了B,新节点的startIndex移动到了B。
在这里插入图片描述
第五次循环中,与第四次循环一样,因此diff后创建了B真实节点,插入到前一次创建的A节点后面。同时旧节点的startIndex移动到了C,新节点的startIndex移动到了F。
在这里插入图片描述
新节点的startIndex已经大于endIndex了,需要创建newStartIdx和newEndIdx之间的所有节点,也就是节点F,直接创建节点F对应的真实节点放到B节点后面。
在这里插入图片描述
3、原理分析
当数据发生改变时,set方法会调用Dep.notify通知所有订阅者Watcher,订阅者就会调用patch给真实的DOM打补丁,更新相应的视图。
源码位置:/src/core/vdom/patch.js
在这里插入图片描述
在这里插入图片描述
patch函数前两个参数位为oldVnode和Vnode,分别代表新的节点和之前旧的节点,主要是做了4个判断。
没有新节点,直接触发旧节点的destory钩子
没有旧节点,说明是页面刚开始初始化的时候,此时根本不需要比较,直接全是新建,所以调用createElm
旧节点和新节点自身一样,通过saveVnode判断节点是否一样,一样时直接调用patchVndoe去处理这两个节点
旧节点和新节点自身不一样,当两个节点不一样时,直接创建新节点,删除旧节点。

下面分析下patchVnode部分:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
patchVnode主要做了以下几个判断:
新节点是否为文本节点,如果是,则直接更新dom的文本内容为新节点的文本内容
新节点和旧节点如果都有子节点,则处理比较更新子节点
只有新节点有子节点,旧节点没有,那就不用比较了,所有节点都是全新的,所以直接全部新建就好了,新建是指创建出所有新的DOM,并且添加进父节点
只有旧节点有子节点,新节点没有,说明更新后的页面,旧节点全部都不见了,那么要做的就是把所有旧节点删除,也就是直接把DOM删除

子节点不完全一致,则调用updateChildren
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
while主要是处理了以下5个场景:
当新老Vnode节点的start相同时,直接patchVndoe,同时新老Vnode节点的开始所以都加1
当新老Vnode节点的end相同时,同样直接patchVnode,同时新老Vnode节点的结束所以都减1
当老节点Vndoe的start和新Vnode节点的end相同时,这时候patchVndoe后,还需要将当前真实dom节点移动到oldEndVnode的后面,同时老Vnode节点开始索引加1,新Vnode节点的结束所以减1
当老Vnode节点的end和新Vnode节点的start相同时,这时候patchVnode后,还需要将当前真实dom节点移动到oldStartVnode的前面,同时老Vnode节点结束索引减1,新Vnode节点的开始索引加1
如果都不满足上述4种情况,那说明没有相同的节点可以复用,则会分为以下两种情况。
从旧的Vnode为key的值,对应index序列为value值的哈希表中找到与newStartVnode一致key的旧的Vnode节点,再进行patchVndoe,同时将这个真实dom移动到oldStartVnode对应的真实dom的前面
调用createElm创建一个新的Dom节点放到当前newStartIdx的位置。

4、小结
当数据发生改变时,订阅者watcher就会调用patch给真实的dom打补丁
通过isSameVNode进行判断,相同则调用patchVnode方法

patchVnode做了以下操作:
找到对应的真实dom,称为el
如果都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
如果oldVnode有子节点而Vnode没有,则删除el子节点
如果oldVnode没有子节点而Vnode有,则将Vnode的子节点真实化后添加到el
如果两者都有子节点,则执行updateChildren函数比较子节点

updateChildren主要进行以下操作:
设置新旧Vnode的头尾指针
新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程,调用createElem创建一个新节点,从哈希表寻找key一致的Vnode节点再分情况操作。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

telnet检验网络能不能通

telnet检测网络能不能通(ip地址端口号)

牵着她——表白不成功算我输(Python实现)

目录 1 牵着她的手一直走下去 2 一首小情诗送给甜甜的她 3 历史总结的哲学想法 4 表白不成功算我输(Python代码) 1 牵着她的手一直走下去 今天牵着她的手,她很贴心。一起并肩赏樱花🌸。骑着快车,清风抚摸着我俩的…

【Spring】bean的生命周期

1.具体的生命周期过程 bean对象创建(调用无参构造器) 给bean对象设置属性 bean对象初始化之前操作(由bean的后置处理器负责) bean对象初始化(需在配置bean时指定初始化方法) bean对象初始化之后操作&am…

STM32F103——基础篇

目录 1、寄存器基础知识 2、STM32F103系统架构 2.1 Cortex M3 内核&芯片 2.2 STM32F103系统架构 3、存储器映射 4、寄存器映射 4.1 寄存器描述解读 4.2 寄存器映射举例 4.3 寄存器地址计算 4.4 stm32f103xe.h 寄存器映射 1、寄存器基础知识 概念:寄存…

pandas read excel 更改string列为时间类型

设想我们有如下一个excel文件 我们都知道上面那个时间列其实是string类型,因此在用pandas做时间校验的时候会不通过,我们可以在read_excel的时候,指定这一列做转换 import pandas as pd from datetime import datetime, timedelta import n…

MySQL — 存储引擎

文章目录 存储引擎存储引擎类型InnoDBMyISAMMEMORY 存储引擎是数据库的核心,对于mysql来说,存储引擎是以插件的形式运行的。虽然mysql支持种类繁多的存储引擎,但是常用的就那么几种。这篇文章主要是对其进行简单的介绍。 存储引擎 MySQL可插…

项目实战 — 消息队列(3){数据库操作}

目录 一、SQLite 🍅 1、添加依赖 🍅 2、修改配置文件后缀(properties -> yaml) 🍅 3、编写配置文件 二、建立数据表 三、添加插入和删除方法 四、整合数据库操作(DataBaseManger类) &a…

go Channel

channel 单纯地将函数并发执行是没有意义的。函数与函数之间需要交换数据才能体现出并发执行函数的意义。 虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中很容易发生竞态问题。为了保证数据交换的准确性,必须使用互斥量对内存进行…

STM32基础入门学习笔记:开发板 电路原理与驱动编程

文章目录: 一:触摸按键 1.触摸按键驱动程序(点击) touch_key.h touch_key.c main.c 2.按键双击和长按程序 touch_key.h touch_key.c main.c 3.触摸按键滑动程序 main.c 二:数码管显示 1.数码管RTC时钟LE…

MCUXpresso for VS Code -- 基于VSCode开发RT1176

MCUXpresso for VS Code 是nxp推出插件,旗下MCX LPC, Kinetis和i.MX rt等MCU,都能在VS Code平台进行嵌入式开发。功能框图如下: 前期准备: 软件环境: windows(实际可以跨系统,linux和mac没有测试) VS Code ninja CMa…

git之reflog分析

写在前面 本文一起看下reflog命令。 1:场景描述 在开发的过程中,因为修改错误,想要通过git reset命令恢复到之前的某个版本,但是选择提交ID错误,导致多恢复了一个版本,假定,该版本对应的内容…

【Linux】进程间通信——system V共享内存

目录 写在前面的话 System V共享内存原理 System V共享内存的建立 代码实现System V共享内存 创建共享内存shmget() ftok() 删除共享内存shmctl() 挂接共享内存shmat() 取消挂接共享内存shmdt() 整体通信流程的实现 写在前面的话 上一章我们讲了进程间通信的第一种方式…

【2023年电赛国一必备】A题报告模板--可直接使用

任务 图1 任务内容 要求 图2 基本要求内容 图3 发挥部分内容 说明 图4 说明内容 评分标准 图5 评分内容 正文 (部分) 摘要 本实验旨在设计和制作一个由两个单相逆变器组成的并联系统,用于为电阻负载供电或并入220V电网。采用基于STM…

[openCV]基于拟合中线的智能车巡线方案V2

import cv2 as cv import os import numpy as np# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir:文件夹根目录输入 ext: 扩展名返回: 文件路径列表"""newDir d…

ospf于mgre中应用(直连与星型拓扑)

题目 地址配置 R1: R2: R3: R4: R5: ISP: R1/2/3的星型拓扑结构 R1配置: interface Tunnel0/0/0 ip address 192.168.6.1 255.255.255.0 tunnel-protocol gre p2mp source 200.1.1.1 ospf …

Docker网络模型使用详解(2)Docker网络模式

安装Docker时会自动创建3个网络,可以使用docker network ls命令列出这些网络。 [rootlocalhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE ebcfad6f4255 bridge bridge local b881c67f8813 compose_lnmp_lnmp…

blender凹凸感和置换形变

一、怎么做出凹凸感 需要三个部分的内容: 1、一个基础的纹理:告诉计算机需要用一个什么样的纹理做凹凸,纹理一般采用黑白,在计算机里面,从 0 - 1之间的值可以用从黑到白之间不同的灰度来表示因此,有一张黑白…

linuxARM裸机学习笔记(3)----主频和时钟配置实验

引言:本文主要学习当前linux该如何去配置时钟频率,这也是重中之重。 系统时钟来源: 32.768KHz 晶振是 I.MX6U 的 RTC 时钟源, 24MHz 晶振是 I.MX6U 内核 和其它外设的时钟源 1. 7路PLL时钟源【都是从24MHZ的晶振PLL而来…

大数据教材推荐|Python数据挖掘入门、进阶与案例分析

主 编: 卢滔,张良均,戴浩,李曼,陈四德 出版社: 机械工业出版社 内容提要 本书从实践出发,结合11个“泰迪杯”官方推出的赛题,按照赛题的难易程度进行排序,由浅入深…

20天突破英语四级高频词汇——第①天

20天突破英语四级高频词汇~第一天加油(ง •_•)ง💪 🐳博主:命运之光 🌈专栏:英语四级高频词汇速记 🌌博主的其他文章:点击进入博主的主页 目录 20天突破英语四级…