vue diff算法与虚拟dom知识整理(12) patch精细化比较新增子节点

news2024/11/27 21:00:13

上文中我们编写了patch函数中对相同节点的几种处理 将简单的都写完了 但还留下了最麻烦的子节点比较
既新旧节点都有子节点 需要 精细化比较

我们先将src下的入口文件index.js 代码改成这样

import h from "./snabbdom/h";
import patch from "./snabbdom/patch";

const container = document.getElementById("container");

const vnode = h("section", {}, [
  h("p", {key:"a"}, "a"),
  h("p", {key:"b"}, "b"),
  h("p", {key:"c"}, "c")
]);

patch( container, vnode)

const btn = document.getElementById("btn");
const vnode1 = h("section", {},[
  h("p", {key:"a"}, "a"),
  h("p", {key:"b"}, "b"),
  h("p", {key:"c"}, "c"),
  h("p", {key:"d"}, "d")
]);

btn.onclick = function(){
  patch( vnode, vnode1)
}

新节点就比老节点多一个子节点
我们这边更新子节点 也分三种情况

其实处理我们这个最后多一个节点的逻辑是会比较简单的 因为他的节点是 以新节点为基础 一个一个节点去遍历的
判断如果有 就好 没有就加上

而我们key的作用在于 如果 第一个子节点 新旧节点都是li 一个内容是 c 一个内容是 a 如果你两个节点都没有key 那么 他就会确认到 key和标签名都相同 因为 标签名都是li key都没设置 就是undefined 那么他就会判断为 是同一个节点 只是文本不一样 这样 他就会将你的 a 替换文本成c
但你如果 设置了key 他就不会乱动你的东西 而是认真判断

然后 我们就可以来写这块最复杂的代码了 当新旧节点都有子节点
在这里插入图片描述
我们先编写代码如下

//当新旧节点都有子节点
//遍历写节点的子元素
newVnode.children.map(news => {
    //定义 isExist  判断新节点中有没有和旧节点一样的元素
    let isExist = false;
    //遍历旧节点子集
    oldVnode.children.map(old => {
        //判断  如果有一模一样的元素  什么都不用做
        if(old.sel == news.sel &&old.key == news.key) {
            isExist = true;
        }
    })
    //判断  如果在旧节点中没有找到相同的节点 就输出出来
    if(!isExist){
        console.log(news);
    }
})

这里 我们先遍历新节点的所有子节点 然后遍历旧节点的所有子节点 对每一个新节点进行判断 找找看 旧节点的子节点中有没有和当前节点相同的 如果没有 我们就输出出来
然后 我们运行项目
在这里插入图片描述
然后 我们点击更改dom
在这里插入图片描述
这里 key为d的节点被输出了
我们看到index.js
在这里插入图片描述
我们可以很明显的看到 确实是只有 d 在旧节点中找不到相同的元素

然后 我们可以进而将代码改写成这样

//当新旧节点都有子节点
//定义un用于记录当前更新的元素下标
let un = 0;
//遍历写节点的子元素
newVnode.children.map((news,index) => {
    //定义 isExist  判断新节点中有没有和旧节点一样的元素
    let isExist = false;
    //遍历旧节点子集
    oldVnode.children.map(old => {
        //判断  如果有一模一样的元素  什么都不用做
        if(old.sel == news.sel &&old.key == news.key) {
            isExist = true;
        }
    })
    //判断  如果在旧节点中没有找到相同的节点 就输出出来
    if(!isExist){
        //通过createElement将虚拟节点变成真正的孤儿节点
        let dom = createElement(news);
        //当当前下标的子节点的elm属性记录上这个新创建的孤儿节点
        news.elm = dom;
        //判断un是不是已经大于了子节点创的   如果是 表示这个下标在老节点找不到
        if(un < oldVnode.children.length) {
            //在老节点对应un下标的前面插入这个节点
            oldVnode.elm.insertBefore(dom, oldVnode.children[un].elm);
        }else{
            //直接在老节点的最后面插入
            oldVnode.elm.appendChild(dom);
        }
    }else{
        //否则就表示 本次循环中 子元素找到了相同的元素 将un+1
        un++;
    }
})

我们通过un记录下标 然后 我们循环遍历新节点 在新节点的变量中定义isExist 这个用来记录当前这个节点有没有相同的

然后遍历老节点 在老节点的遍历中 找有没有与新节点子元素相同
例如 我们新节点 是 a b c d 老节点是 a b c 那我 新节点遍历子节点 第一次进来的是 a 他就会循环遍历老节点的子节点 第一次 就 新节点的a和老节点下面的a是一样的
达到条件之后就会复制isExist 为ture记录
这个大家不用担心 第二次 b进循环 isExist 声明的这个代码就会创新执行 他还是初始值 false
然后 走出老节点的循环 还在新节点的循环中 还是那a节点举例 我们判断isExist
如果他不是 false 表示 新节点和老节点都有这个元素 我们就将un加一 用于记录 这个节点已经被记录了

那么 不同的只有新节点的d了
d进来 因为找不到一样 的 到最后判断isExist 就还是false
然后 我们还是通过createElement 将这个虚拟节点 变成一个真实的孤儿节点
然后 然后 news记录的就是d本身 因为 他是我们循环新节点子节点的下标 就是当前循环的元素
我们直接将新创建的孤儿节点存到当前虚拟节点的elm中
然后判断
un是不是大于旧节点的子节点数量

如果不大于 直接插入在新节点un下标的子节点的前面
例如 如果
旧节点是 a b c
新节点是 a d b c
这样 第一次 进来 a和a相同
isExist 是true un++
现在un是1
然后 第二次进来 d 找不到相同的 就会 执行到判断 un是不是大于旧节点的数量
旧节点有三个子元素 un是1 显然un小于旧节点的子集
那就执行
oldVnode.elm.insertBefore(dom, oldVnode.children[un].elm);
通过就节点的elm拿到旧节点的真实dom节点作为父级调用insertBefore 将用d虚拟节点创建的孤儿节点插入在旧节点的 un下标的节点前面 那么 旧节点的 1 下标 就是 b节点 因为下标是从零开始的
那么 旧节点此时就变成了 adbc
按我现在的路径走到 判断un时 他是大于旧节点的子集的
那么 直接就用appendChild 将他插入在 旧节点的elm的最后面
我们运行项目
在这里插入图片描述
点击更新dom
在这里插入图片描述
我们的d 就上去了

在这里插入图片描述
我们现在来换个顺序
index.js 代码修改如下

import h from "./snabbdom/h";
import patch from "./snabbdom/patch";

const container = document.getElementById("container");

const vnode = h("section", {}, [
  h("p", {key:"a"}, "a"),
  h("p", {key:"b"}, "b"),
  h("p", {key:"c"}, "c")
]);

patch( container, vnode)

const btn = document.getElementById("btn");
const vnode1 = h("section", {},[
  h("p", {key:"a"}, "a"),
  h("p", {key:"d"}, "d"),
  h("p", {key:"b"}, "b"),
  h("p", {key:"c"}, "c")
]);

btn.onclick = function(){
  patch( vnode, vnode1)
}

这就是我们上面的举例
我们运行项目
在这里插入图片描述
点击 更改dom
在这里插入图片描述
也是没有任何问题

那么 问题来了 如果是交换顺序呢?

我们更改 index.js 代码如下

import h from "./snabbdom/h";
import patch from "./snabbdom/patch";

const container = document.getElementById("container");

const vnode = h("section", {}, [
  h("p", {key:"a"}, "a"),
  h("p", {key:"b"}, "b"),
  h("p", {key:"c"}, "c")
]);

patch( container, vnode)

const btn = document.getElementById("btn");
const vnode1 = h("section", {},[
  h("p", {key:"a"}, "a"),
  h("p", {key:"c"}, "c"),
  h("p", {key:"b"}, "b")
]);

btn.onclick = function(){
  patch( vnode, vnode1)
}

我们将 b和c的顺序换一下
但我们现在点击是没有任何效果的
在这里插入图片描述
因为 我们只考虑了元素新增 还没有处理老节点的调整
下文 我们继续来处理一下 老节点的节点变化

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

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

相关文章

C++实现Canny边缘检测(原理+底层代码)

文章目录 一、算法原理二、环境配置三、算法详解3.1、数据结构 Mat3.2、高斯滤波器的C实现3.3、用一阶偏导有限差分计算梯度幅值和方向 三、项目实战&#xff1a;C实现Canny边缘检测 一、算法原理 canny边缘检测算法步骤&#xff1a; 1、使用高斯滤波器对图像进行平滑处理。 2、…

recurdyn履带问题

1.问题&#xff1a;整车履带仿真出错&#xff0c;车辆越障时遇到障碍物直接弹开 思路&#xff1a; 关于这类模型需要调节履带和地面之间的接触参数、Bushing force&#xff0c;还有驱动函数。 弹飞了是因为接触刚度太大了&#xff0c;调小一些&#xff0c;在100以内继续调节…

从代码角度理解DETR

一个cnn的backbone, 提图像的feature, 比如, HWC.同时对这个feature做position_embedding.然后二者相加 (在Transformer里面就是二者相加)输入encoder,输入decoder (这里有object queries.)然后接Prediction Heads, 比如分类和回归. 下面的代码参考自: https://github.com/fac…

单片机原理及应用——持续更新

目录 一、单片机概述 1、单片机简介 2、单片机的特点 3、MSC-51系列与AT89S5x系列单片机 &#xff08;1&#xff09;MSC-51系列单片机 &#xff08;2&#xff09;AT89S5x系列单片机 二、AT89S52单片机的片内硬件结构 1、AT89S52单片机的硬件组成 2、AT89S52单片机的引…

Springboot +spring security,OAuth2 四种授权模式概念

一.简介 这篇文章来讲下Spring Security OAuth2 四种授权模式。 二.什么是OAuth2 OAuth 2.0 是一种用于授权的开放标准&#xff0c;允许用户授权第三方应用程序访问他们的资源&#xff0c;例如照片、视频或其他个人信息。OAuth 2.0 提供了一些不同的授权模式&#xff0c;包括…

我有一个朋友,分享给我的字节跳动测试开发真题

朋友入职已经两周了&#xff0c;整体工作环境还是非常满意的&#xff01;所以这次特意抽空给我写出了这份面试题&#xff0c;而我把它分享给小伙伴们&#xff0c;面试&入职的经验&#xff01; 大概是在3月中的时候他告诉我投递了简历&#xff0c;5月的时候经过了3轮面试收获…

Windows10中搭建ftp服务器以实现文件传输

开启ftp服务&#xff1a; 1、打开控制面板》程序和功能》 启用或关闭Windows功能 2、找到Internet Information Services&#xff0c;开启以下服务 勾选之后&#xff0c;ftp服务开启成功。 配置IIS&#xff0c;搭建ftp 1、WinS键搜索iis&#xff0c;回车打开》右击网站 》添加…

QUIC 协议:特性、应用场景及其对物联网/车联网的影响

什么是 QUIC 协议 QUIC&#xff08;Quick UDP Internet Connections&#xff09;是由谷歌公司开发的一种基于用户数据报协议&#xff08;UDP&#xff09;的传输层协议&#xff0c;旨在提高网络连接的速度和可靠性&#xff0c;以取代当前互联网基础设施中广泛使用的传输控制协议…

/dev/kmem /proc/kallsyms

文章目录 前言概述使用 /dev/kmem使用 /proc/kallsyms验证进阶 前言 上篇文章我们介绍了 /dev/mem&#xff0c;今天再来介绍下它的好兄弟 /dev/kmem crw-r----- 1 root kmem 1, 1 May 26 06:10 /dev/mem crw-r----- 1 root kmem 1, 2 May 26 06:10 /dev/kmem对比一下&#xf…

第十四届全国大学生数学竞赛决赛(非数类)游记+答案解析

2023/5/27 20:08&#xff1a;今天早上9:00~12:00考了数学竞赛国赛。广州是真的热啊&#xff01;西安才17度&#xff0c;还下着小雨&#xff0c;到广州之后那个艳阳直接给我人干废了&#xff0c;去酒店的路上步行了20分钟真的要死了已经。 拿到卷子的我是崩溃的&#xff0c;用正…

计算机视觉:填充(padding)技术

本文重点 在前面的课程中,我们学习了使用3*3的过滤器去卷积一个5*5的图像,那么最终会得到一个3*3的输出。那是因为 33 过滤器在 55 矩阵中,只可能有 33 种可能的位置。 这背后的数学解释是,如果我们有一个nn的图像,用ff的过滤器做卷积,那么输出的维度就是(n−f+1)(n−f…

码出高效_第一章 | 有意思的二进制表示及运算

目录 0与1的世界1.如何理解32位机器能够同时处理处理32位电路信号&#xff1f;2.如何理解负数的加减法运算3.溢出在运算中如何理解4.计算机种常用的存储单位及转换5.位移运算规则6.有趣的 && 和 & 浮点数1.定点小数&#xff08;为什么会出现浮点数表示&#xff1f;…

Linux 系统烧写

目录 MfgTool 工具简介MfgTool 工作原理简介烧写方式系统烧写原理 烧写NXP 官方系统烧写自制的系统系统烧写网络开机自启动设置 改造我们自己的烧写工具改造MfgTool烧写测试解决Linux 内核启动失败 前面我们已经移植好了uboot 和linux kernle&#xff0c;制作好了根文件系统。但…

Spring 事件相关知识ApplicationEvent

Spring 事件相关知识ApplicationEvent 事件工作流程相关类ApplicationListenerApplicationEvent 我们可以发布自己的事件ApplicationEventPublisher Spring框架中提供了多种事件类型&#xff0c;常用的几个事件类型如下&#xff1a; Spring 事件驱动模型是 Spring 框架中的一个…

uCOSii中的事件标志组

事件标志管理 (EVENT FLAGS MANAGEMENT) OSFlagAccept() 无等待查询”事件标志组的事件标志位”是否建立 OSFlagPend() 需要等待”事件标志组的事件标志位”建立 OSFlagCreate() 建立一个事件标志组 OSFlagDel() 删除一个事件标志组 OSFlagPost() 置位或清0事件标志组中的…

SpringBoot整合百度云人脸识别功能

SpringBoot整合百度云人脸识别功能 1.在百度官网创建应用 首先需要在百度智能云官网中创建应用&#xff0c;获取AppID&#xff0c;API Key&#xff0c;Secret Key 官网地址&#xff1a;https://console.bce.baidu.com/ 2.添加百度依赖 添加以下依赖即可。其中版本号可在mav…

【问卷分析】调节效应检验的操作①

文章目录 1.首先要明白自己的调节和自变量是什么类别的2.实操演练2.1 当调节变量是连续变量时2.1.1 将ml中心化2.1.2 使用分层回归探讨自变量和ml的交互对adh的影响2.1.3 结果解读 1.首先要明白自己的调节和自变量是什么类别的 2.实操演练 在本次演练中&#xff0c;我们以自变…

马斯克要用人工智能对抗人工智能

导读&#xff1a;马斯克对人工智能可能变得失控并“摧毁人类”的担忧促使他采取行动&#xff0c;发起了一个名为“TruthGPT”的项目。 本文字数&#xff1a;1400&#xff0c;阅读时长大约&#xff1a;9分钟 亿万富翁埃隆马斯克在谈到人工智能&#xff08;AI&#xff09;的危险时…

瑞合信LED字幕WiFi卡使用教程(8.0版)

请按照提示下载和安装软件&#xff0c;同时请允许所有权限&#xff0c;如下图&#xff1b; 也可以在各大主流应用商店&#xff08;华为、小米、OPPO、vivo、App Store等&#xff09;搜索“瑞合信”直接安装。 首次使用APP时会提示注册登录软件&#xff0c;你可以选择“使用微信…

深度学习进阶篇-预训练模型[4]:RoBERTa、SpanBERT、KBERT、ALBERT、ELECTRA算法原理模型结构应用场景区别等详解

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…