vue diff算法与虚拟dom知识整理(15) 终结篇,收尾新前到旧前全部不匹配情况

news2024/12/24 8:18:22

我们现在就只需要处理最后一种情况了

我们在 updateChildren.js
在while中
在这里插入图片描述
的if最后加个 else
在这里插入图片描述
当他们都没哟匹配到的情况

我们现在在updateChildren.js最上面 定义一个空对象 叫 keyMap
参考代码如下

let keyMap = null;

在这里插入图片描述

然后 在我们刚写的else中编写代码如下

//判断  如果没有keyMap  表示之前没有处理过
if(!keyMap){
    //将keyMap 转成一个对象
    keyMap = {};
    //循环遍历  条件为旧前加到大于旧后  简单说遍历所有 旧节点的子节点
    for (let i = oldStartIdx; i <= oldEndIdx; i++) {
        //先存入对应子节点的key
        const key = oldch[i].key;
        //判断如果是undefined就不要进来了
        if (key != undefined) {
            keyMap[key] = i;
        }
    }
}
console.log(keyMap);
newStartIdx++;

在这里插入图片描述
简单说 我们判断 如果所有条件都不匹配 就先看看 keyMap中有没有内容 如果没有 就将他设置为一个真的对象 然后 循环所有的旧节点的子节点集合 拿取每一个子节点key 如果key不是undefined 就将key和下标记录给keyMap
最后打印一下结果在控制台 顺手将新前newStartIdx节点加一 因为 如果你不处理 他会死循环的

我们马上来试一下效果
将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"),
  h("p", {key:"d"}, "d")
]);

patch( container, vnode)

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

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

这样 肯定是不管他什么新前旧前的都匹配不上了 因为我们就一个 QQQ 是旧节点压根没有的

然后我们运行项目
在这里插入图片描述
然后点击 更改dom
在这里插入图片描述
可以看到 内容全没了 控制台也成功输出了旧节点的key和下标

这里 没了是因为 我们上文写的 while下面那个旧节点删除的逻辑将他们都处理掉了
在这里插入图片描述
但现在显然我们要想办法把这个qqq弄上去

我们在这个console.log(keyMap); 后面在加一段代码

//从keyMap中去寻找和新前节点的key相同的节点下标  然后赋值给idxInold
const idxInold = keyMap[newStartVnode.key];
console.log(idxInold);

在这里插入图片描述
因为 新前肯定是我们正在处理的这个节点 我们去匹配一下 keyMap 中的内容
如果有和新前key一样的 就取过来 如果没有 我们取到的就是个undefined
我们运行项目 然后点击 更改dom 查看控制台
在这里插入图片描述
很显然 他输出了undefined
因为旧节点的子节点中 并没有key为QQQ的子节点
我们可以改一些src下的index.js
将 vnode1 改为

const vnode1 = h("section", {},[
  h("p", {key:"c"}, "QQQ")
]);

然后我们运行项目 点击更改dom
在这里插入图片描述
可以看到 这次我们就取到了

那么 这个就非常简答了 如果 最后
idxInold不是undefined 表示 旧节点中有这个节点 需要更改一下
如果是undefined 表示 新前就是个全新的节点 需要插入进去

但在这之前 我们要改一下代码
updateChildren.js中的while循环开头加入这样的逻辑代码

//判断如果旧前节点是空的  控制指针后移
if (oldStartVnode == null || oldch[oldStartIdx] == undefined) {
    oldStartVnode = oldch[++oldStartIdx];
//判断旧后如果是空的  将旧后向前移一个
} else if (oldEndVnode == null || oldch[oldEndIdx] == undefined) {
    oldEndVnode = oldch[--oldEndIdx];
//判断  新前节点如果是空的  则向后移动一个节点
} else if (newStartVnode == null || newCh[newStartIdx] == undefined) {
    newStartVnode = newCh[++newStartIdx];
//然后判断  新后节点是空的 向前移动一个节点
} else if (newEndVnode == null || newCh[newEndIdx] == undefined) {
    newEndVnode = newCh[--newEndIdx];
}

注意 就和之前的if连在一起 如下图
在这里插入图片描述
如果新前 新后 旧前 旧后取不到值 就做一下处理 向前 或向后处理一个节点 保证这个节点是存在的

然后我们在我们刚写的这个

const idxInold = keyMap[newStartVnode.key];

下面 编写代码如下

//判断 如果idxInold是undefined  表示新前是一个全新的节点
if (idxInold == undefined) {

}else{
// 否则表示   旧节点中也有这个节点 需要精细化和移动处理
    //先将要处理的老节点存出来
    const elmToMove = oldch[idxInold];
    //通过patchVNode对新老节点做精细化比较处理
    patchVNode(newStartVnode,elmToMove);
    //然后在旧节点的集合中将这一项设置为undefined  避免在下面被删除旧节点干掉
    oldch[idxInold] = undefined;
    //将处理好的节点  移动到 旧前节点的前面
    parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm);
}
//将新前节点后移
newStartVnode = newCh[++newStartIdx];

这里 我们判断 拿到的idxInold 是不是undefined 就是判断 当前新前节点在旧节点的子节点中是否存在
我们这里 直接先写else 就是 存在 他不为undefined

那么 我们先用elmToMove 记录下旧的这个节点的内容
然后 用patchVNode对他们做精细化比较赋值处理

然后将原本旧节点的这个 赋值为undefined 然后 通过insertBefore 将节点移动到当前旧前

然后 我们下面这个旧节点删除的处理要优化下
在这里插入图片描述
简单说 判断一下 确认 oldch[i] 是存在的再继续往下走

然后 我们此时运行项目
在这里插入图片描述
点击 更改dom
在这里插入图片描述
可以看到 我们 key为c 值为 QQQ的节点就上来了

梳理一下逻辑 首先 第一次
新前新后都是 c
旧前是 a 旧后是 d

此时 四个值都有 所以最前面的几个条件达不到 然后 新前旧前 新后旧后 旧前新后这些都不一样
所以直接走进了最后的else
然后 新前在旧子节点中匹配出了c节点 然后 通过patchVNode做了精细化比较 在将原来旧节点的这个c节点赋值为了undefined
然后 通过insertBefore 将新前(处理了精细化比较的c节点) 移动到目前旧前节点 a 前面
然后 将新前节点 向后推1
因为 新前节点 加一之后就等于1了 而新后节点是接的新节点的子节点长度-1 新节点只有一个子节点
那么 新后就是0 所以 新前大于了新后 循环结束 走人后面两个判断
走进旧节点上传 就将多余部分干掉了
所以 我才叫大家加上那个判断 因为你赋值为undefined之后 他处理完 这个节点在删除循环中是会报错的 要判断 确定有才做删除操作

然后 我们将 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"),
  h("p", {key:"d"}, "d")
]);

patch( container, vnode)

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

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

然后 我们再运行项目
在这里插入图片描述
然后 我们点更改dom
这样就废了
在这里插入图片描述
啥都没了 因为我们并没有写这个新增节点的处理

我们在 if (idxInold == undefined) {
下面加入

//通过 createElement  将newStartVnode新前节点变成孤儿节点  然后插入在 oldStartVnode旧前节点前面
parentElm.insertBefore(createElement(newStartVnode), oldStartVnode.elm)

然后 我们运行项目

在这里插入图片描述
然后点击更改dom
在这里插入图片描述
我们的更新就成功了

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

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

相关文章

Stable-Diffusion|入门怎么下载与使用civitai网站的模型(二)

C站&#xff1a;https://civitai.com/ 文章目录 1 样图2 实现2.1 下载主模型并放到正确文件夹中2.2 找到prompt2.3 生成2.4 Lora使用 3 一些有趣的项目3.1 胶片风格Lora3.2 [最近很火] 现实感很强的Majicmix-realistic 先贴几张笔者自己实验的图&#xff0c;模型来自&#xff1…

Libevent学习

一、Libevent概述 1、简介 Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库&#xff0c;主要有以下几个亮点&#xff1a;事件驱动&#xff08; event-driven&#xff09;&#xff0c;高性能;轻量级&#xff0c;专注于网络&#xff0c;不如 ACE 那么臃肿庞大&…

C++必背基础知识点总结

重点&#xff1a;不借助任何外部资料就能掌握&#xff0c;考试面试大概率涉及。 掌握&#xff1a;不借助任何外部资料就能掌握&#xff0c;考试面试有可能涉及。 熟悉&#xff1a;可以适当参考资料掌握&#xff0c;考试面试有可能涉及。 了解&#xff1a;可是参考资料掌握&…

iptables的四表五链

文章目录 1. Iptables的链2.Iptables的表3.数据包过滤的匹配流程3.1 规则表之间的顺序3.2 规则链之间的顺序3.3 规则链内部各条防火墙规则之间的顺序3.4如何应用 每个 规则表&#xff0c;其实就相当于一个内核空间的容器&#xff0c; 按照规则集的不同用途进行划分为默认的四…

w11+wsl+3060安装cuda等深度学习环境

把一切都重新又梳理学习了一遍&#xff0c;然后发现很多事情其实没必要弄 0. 显卡驱动、nvidia-smi、cuda、nvcc、cuDNN、pytorch、cudatoolkit与它们之间的关系 笔者本人鸟枪换炮了&#xff0c;还是wsl环境香&#xff0c;但是按照官方教程跑完后&#xff0c;遇到了bugRuntim…

RTMPose关键点检测实战——笔记3

文章目录 摘要安装MMPose安装虚拟环境安装pytorch安装MMCV安装其他的安装包下载 MMPose下载预训练模型权重文件和视频素材 安装MMDetection安装Pytorch安装MMCV安装其它工具包下载 MMDetection安装MMDetection下载预训练模型权重文件和视频素材 MMPose预训练模型预测命令行的方…

关于render: h => h(App)的解释

当我们第一次安装完脚手架&#xff0c;打开 的时候&#xff0c;我相信&#xff0c;一定有小伙伴和我一样&#xff0c;看到main.js里面的render: h > h(App),感觉懵懵的。 因为&#xff0c;在刚开始接触vue的时候&#xff0c;我们这里是这样写的&#xff1a; 而使用了脚手…

iOS性能优化-异步绘制与异步底层View处理

前言&#xff1a; 基于UIKit的性能优化似乎已经到了瓶颈&#xff0c;无论是使用frame代理snpakit&#xff0c;缓存高度&#xff0c;减少布局层次&#xff0c;diff刷新&#xff0c;压缩图片&#xff0c;选择合适队列&#xff0c;选择高性能锁&#xff0c;也不能满足当前庞大而又…

SpringBoot 整合 MongoDB 实现数据的增删改查功能

1、介绍说明 在 MongoDB 中有三个比较重要的名词&#xff1a;数据库、集合、文档 数据库&#xff08;Database&#xff09;&#xff1a;和关系型数据库一样&#xff0c;每个数据库中有自己的用户权限&#xff0c;不同的项目组可以使用不同的数据库 集合&#xff08;Collectio…

汽车新能源 - 单体电压值为什么通常是5V以内

常见蓄电池单体电压的值&#xff08;25℃&#xff09;&#xff0c;如下表&#xff1a; 蓄电池类型单体电压&#xff08;V&#xff09;铅酸 蓄电池2.08镍金属氢 蓄电池&#xff08;NIMH&#xff09;1.32锂离子 蓄电池2.5~4.2&#xff08;典型3.6&#xff09; 单体电压为什么不…

安卓学习笔记(一)

从今天开始我们开始学习安卓的知识&#xff1a; 1.0 Android基础入门教程 1.Android背景与当前的状况 Android系统是由Andy Rubin创建的&#xff0c;后来被Google收购了&#xff1b;最早的版本是:Android 1.1版本 而现在最新的版本是今年5.28&#xff0c;Google I/O大会上推…

Logstash部署与使用

ElasticSearch 1、ElasticSearch学习随笔之基础介绍 2、ElasticSearch学习随笔之简单操作 3、ElasticSearch学习随笔之java api 操作 4、ElasticSearch学习随笔之SpringBoot Starter 操作 5、ElasticSearch学习随笔之嵌套操作 6、ElasticSearch学习随笔之分词算法 7、ElasticS…

123网盘在线解析PHP版源码

123网盘解析PHP版本源码是一种非常实用的工具&#xff0c;可以方便地帮助用户在网页上直接解析出其它网站中的资源&#xff0c;并提供下载链接。当用户需要获取某些资源时&#xff0c;往往需要通过各种搜索引擎或者专业的资源网站进行查找&#xff0c;而且很多时候找到了资源链…

Android NDK集成OpenCV使用C++的.h和.so库函数

Android NDK集成OpenCV使用C的.h和.so库函数 opencv可以作为一个单独的Android module库&#xff0c;被工程下的其他模块使用&#xff0c;但是这样就没法在Android NDK项目的c代码直接使用opencv的.h文件和.so文件。要在Android NDK项目C代码文件中使用&#xff0c;则需要以An…

Nautilus Chain上首个DEX PoseiSwap即将开启IDO

据悉&#xff0c;Nautilus Chain 上的首个 DEX PoseiSwap 即将开启 IDO &#xff0c;根据官方的最新公告显示&#xff0c;PoseiSwap 即将于 6 月 13 日至 6 月 14 日期间&#xff0c;在 Bounce 平台开启其治理通证 $POSE 的 IDO&#xff08;Initial DEX Offering&#xff09;&a…

数据分析--Numpy初级(一)

Numpy初级 Ndarray对象dtype对象 Numpy是数据分析的基础库&#xff0c;它支持大量的维度计算与矩阵运算。同时他也是一个运行速度非常快的数学库&#xff0c;主要用于数组计算&#xff0c;具有线性代数、傅里叶变换、随机数生成等功能。 Ndarray对象 Numpy最重要的一个特点就…

【内部类】

目录 1.什么是内部类2.内部类分类2.1静态内部类2.非静态内部类2.3 局部内部类&#xff08;几乎不用&#xff0c;大家了解&#xff09; 3.匿名内部类 1.什么是内部类 在Java中&#xff0c;可以将一个类定义在一个类中或者在一个方法中&#xff0c;前者称为内部类&#xff0c;后…

JAVA打印Hello World的底层实现

任何一个学过JAVA的人应该都对这段代码非常熟悉。空闲时间翻了下代码&#xff0c;看看它的底层是怎么实现的 public class HelloWorld {public static void main(String[] args) {System.out.print("Hello, World!");} }首先点开out&#xff0c;发现它是System类中的…

JAVA微服务_网关

服务网关 什么是服务网关/API网关 API Gateway&#xff08;APIGW / API 网关&#xff09;&#xff0c;顾名思义&#xff0c;是系统对外的唯一入口。API网关封装了系统内部架构&#xff0c;为每个客户端提供定制的API。 近几年来移动应用与企业间互联需求的兴起。从以前单一的…

数据结构学习记录——图-最短路径问题(无权图单源最短路径算法、有权图单源最短路径算法、多源最短路径算法、Dijkstra(迪杰斯特拉)算法、Floyd算法)

目录 问题分类 无权图单源最短路径算法 思路 伪代码 时间复杂度 代码实现&#xff08;C语言&#xff09; 有权图单源最短路径算法 Dijkstra&#xff08;迪杰斯特拉&#xff09;算法 伪代码 时间复杂度 代码实现&#xff08;C语言&#xff09; 多源最短路径算法 …