vue diff算法与虚拟dom知识整理(6) 感受diff算法 (不要神话虚拟dom更不要做完美主义)

news2025/1/10 20:47:00

我们还是打开之前的案例
然后 将src下的index.js代码修改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

首先 我们写入节点的方法叫 patch
我们来查一下这个单纯的意思
在这里插入图片描述
其实 他不是一个暴力装卸的方法 而是 修补的一个概念

因为 我们需要一个触发事件的工具 所以 我们在www文件夹下的index.html中加一个id为btn的按钮
参考代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id = "btn">更改dom</button>
    <div id="container"></div>
    <script src="/xuni/bundle.js"></script>
</body>
</html>

然后我们改写 src下的index.js代码如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("ul",{},[
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c"),
    h("li",{},"d")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

这里 我们获取了 btn 按钮 给他定义了一个点击事件 点击他 做了一个patch操作
这就是patch的神奇之后 不需要再传节点了 直接传两个需要比较的变量即可
然后我们运行项目
在这里插入图片描述
我们可以看到 现在运行的是 vonm的 abc
我们点击上面按钮
在这里插入图片描述
可以看到 这里就变成了 vonm2的 abcd

这里 我们要清除 不是直接暴力的 把vonm2又渲染上去了 而是对比两者差异 哦 发现只有一个 d不一样 就追加了一个d上去
这是patch的意义

那么 怎么证明呢
我们刷新界面
然后在控制台修改节点的文本
在这里插入图片描述
我们直接在控制台上 通过节点编辑 将a 改成丑八怪
在这里插入图片描述
然后 我们再次点击按钮 如果他是重新渲染 那么 这个a是不是该变回去啊?
那我们点击按钮
在这里插入图片描述
很显然 d出来了 但a没有复原 因为在程序中 他们确认过 第一个节点是一样的 我们在控制台改了内容js并不知道
所以 这就是 diff的好处 最小量更新

但你如果以为他是在最后面插入 那么我们就要思考另一个问题
它怎么实现前面或中间的更改呢?

我们将 src 下的 index.js代码更改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("ul",{},[
    h("li",{},"d"),
    h("li",{},"a"),
    h("li",{},"b"),
    h("li",{},"c")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

这次 我们把D放到最前面
我们运行之后 我们在上面 将 a 改成 丑八怪 b 改成 搭好
在这里插入图片描述我们点击按钮
在这里插入图片描述
会发现 它既然变成了 dabc
在这里插入图片描述
其实 也不是重新渲染 但也差的不多 他把 a 变成了 d , b变成了 a ,c变成了 b 在最后面 又追加了一个c

这里证明的 是因为 前面的也被改了 丑八怪和搭好就被覆盖了
可能 这时 有小伙伴就会想 这也不是很智能啊
不是哦 是我们没有给他加key

我们将 src下的index.js入口文件修改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{key: "a"},"a"),
    h("li",{key: "b"},"b"),
    h("li",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("ul",{},[
    h("li",{key: "d"},"d"),
    h("li",{key: "a"},"a"),
    h("li",{key: "b"},"b"),
    h("li",{key: "c"},"c")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

这次 我们给这些虚拟节点加上了 key属性 然后我们再次运行项目
在这里插入图片描述
我们还是像之前一样 在控制台改一下a b 节点的文本
然后我们点击按钮 改变一下dom
在这里插入图片描述
可以很明显的看到 这次他就没动 a b 节点了 因为我们控制台改的内容并没有被覆盖 说明 这两个节点它没动
只是在最上面加了一个d 这就是key对虚拟dom的作用

key是节点的唯一标识 他能帮助我们完成真正意义上的最小量更新

然后 我们来看第二个东西
将 src下的 index.js代码修改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("ul",{},[
    h("li",{key: "a"},"a"),
    h("li",{key: "b"},"b"),
    h("li",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("ol",{},[
    h("li",{key: "a"},"a"),
    h("li",{key: "b"},"b"),
    h("li",{key: "c"},"c")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

这次 我们不改里面的li标签了 我们直接将他们的父节点 重 ul无序列表改为 ol 有序列表

那最小量更新就是 改一下父标签 对吗?
那么 我们来试一下是不是这样

我们运行项目 就还是在控制台把文本改了
在这里插入图片描述
然后 我们点击更新dom
在这里插入图片描述
可以看到 确实是边有序列表了 但 有没有发现 子节点也被更新了啊?

简单说 只有是同一个节点 才进行精细化 比较 简单说 他在接到这个 ul改ol时 已经视为 两者不是同一个节点了 那就直接暴力拆掉 然后重新装上去
等于 把整个全换了
当 选择器(就是标签类型) 或者 key不同时 他就会视为不是同一个节点
那可能有人会说 那这最小化更新不厉害啊?
但你们仔细想一下 在正式开发中 你们会遇到需要改父节点标签类型的逻辑吗? 所以 这是无伤大雅的 不要做完美主义

所以 这里写的所有内容 都是在vue中会发生的 父节点选择器改变时 子节点是不精细化校验更新的 他直接就旧的拆掉 新的上树 简单说 整个从内到外全换新
面试官面前 这些都可以聊

还有一个经常在文章和公众号文档中出现的 一个概念 只有同层才进行比较 但说的都很笼统 我们来好好研究一下

比如 我们这里 将src/index.js代码修改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("div",{},[
    h("p",{key: "a"},"a"),
    h("p",{key: "b"},"b"),
    h("p",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("div",{},[
    h("p",{key: "a"},"a"),
    h("p",{key: "b"},"b"),
    h("p",{key: "c"},"c")
  ]);

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

我们将他从div下三个p 改为一模一样的内容 然后我们点击按钮更新
在这里插入图片描述
会发现控制台没什么反应 说明 他判断 都是一样的 就不更新了
但我们将 src/index 下的代码更改成这样

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("div",{},[
    h("p",{key: "a"},"a"),
    h("p",{key: "b"},"b"),
    h("p",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("div",{},
    h("div",{},[
      h("p",{key: "a"},"a"),
      h("p",{key: "b"},"b"),
      h("p",{key: "c"},"c")
    ])
  );

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

我们在更改后端内容内多加一层div
这里 我们刚运行项目 这里 节点结构明显是div下三个p
在这里插入图片描述
然后点击 他就变成了 div下一个div 下面三个p
在这里插入图片描述
那么 我们思考 他是否是最小量更新?
最小量更新就是 不要动三个p 在外面多套个div
可以先告诉大家 这个想法太美好了 但现实比较残酷
我们还是 文本测试法

我们在控制台上更改三个p的文本
在这里插入图片描述
然后点击按钮
在这里插入图片描述
让人失望的是 它全部覆盖了

说明的很简单 他把原本的三个p干掉了 然后重新插入了 div里面重写写入了三个p
意思就是 他只有同层会比较 就算你没有换标签 只要 他们层级不一样 也不会再比较了 也就没有精细化比较了

暴力拆掉旧的 强行插入新的
这个操作 我觉得会比上面那个换父标签类型可能更现实一点 但也基本遇不到 所以 没必要做完美主义 人家做开源还懒得做兼容呢 没什么人弄的东西 没必要强求

但同层 就算乱序 也可以最小量比较更新
我们将 src/index代码更改如下

import {
    init,
    classModule,
    propsModule,
    styleModule,
    eventListenersModule,
    h,
  } from "snabbdom";

  //创建patch函数
  const patch = init([
    classModule,
    propsModule,
    styleModule,
    eventListenersModule
  ]);
 
  //创建虚拟节点
  var vonm = h("div",{},[
    h("p",{key: "a"},"a"),
    h("p",{key: "b"},"b"),
    h("p",{key: "c"},"c")
  ]);

  //让虚拟节点上树
  const container = document.getElementById('container');
  patch(container,vonm);

  //定义第二个虚拟dom节点
  var vonm2 = h("div",{},[
      h("p",{key: "b"},"b"),
      h("p",{key: "c"},"c"),
      h("p",{key: "a"},"a")
    ]
  );

  //获取btn节点
  const btn = document.getElementById('btn');

  //监听用户点击按钮
  btn.onclick = function() {
    //属性替换
    patch(vonm,vonm2);
  }

我们这里 前后节点没有结构变化 只是改变了一下 abc的顺序
然后我们运行项目
在这里插入图片描述
还是在控制台更改一下内容
然后点击按钮更新dom
在这里插入图片描述
可以看到 并没有强行去拆 而是做了最小量的比较更新 只是换了顺序 我们更改的文本还在 说明节点没有换
这就是patch内部算法的强大
那么 我之后也会出问题讲一下 patch 并带大家手写一个自己的 patch
好啦 那就到这啦

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

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

相关文章

tcp 三次握手和四次挥手报文分析

1&#xff0c;tcp 三次握手 报文抓取如下&#xff1a; 三段报文分析&#xff1a; 第一次&#xff1a;26->96报文交互 Seq-num 567391014, ACK_NUM 0; flags SYN 第二次&#xff1a;96->26报文交互 Seq-num 416352681, ACK_NUM Seq-num 1 567391014 1 567391015,…

硬件系统工程师宝典(22)-----电容、电感的特性,你都知道吗?

各位同学大家好&#xff0c;欢迎继续做客电子工程学习圈&#xff0c;今天我们继续来讲这本书&#xff0c;硬件系统工程师宝典。上篇我们说到做电阻选型时要考虑阻值、功率、精度和封装大小。上下拉电阻除了给引脚一个稳定的电平&#xff0c;可以提高电压准位、增加输出功率以及…

法律 法规

第八章、法律 法规 从所涉及的法律法规角度 1️⃣著作权法 2️⃣计算机软件保护条例 3️⃣商标法 4️⃣专利法 从试题考点分布的角度 1️⃣保护期限 2️⃣知识产权人确定 3️⃣侵权判断 中国公民、法人或者其他组织的作品&#xff0c;不论是否发表&#xff0c;都享有著作…

Linux服务安装node,npm与yarn

目录 Linux服务安装node&#xff0c;npm与yarn 可以直接在win或者Linux安装node官网&#xff08;中文版&#xff09;下载所需要的版本 通过epel 的来安装 node 安装npm 利用npm安装yarn 卸载yarn 安装依赖 运行 本篇文章仅是本人遇到的问题&#xff0c;希望可以对你有帮…

基于海鸥算法优化的核极限学习机(KELM)分类算法-附代码

基于海鸥算法优化的核极限学习机(KELM)分类算法 文章目录 基于海鸥算法优化的核极限学习机(KELM)分类算法1.KELM理论基础2.分类问题3.基于海鸥算法优化的KELM4.测试结果5.Matlab代码 摘要&#xff1a;本文利用海鸥算法对核极限学习机(KELM)进行优化&#xff0c;并用于分类 1.KE…

Go基础知识入门

1、go语言介绍 2、go开发环境搭建 2.1、go的安装 go下载地址&#xff1a;All releases - The Go Programming Language&#xff0c;windows选择下载go1.20.2.windows-amd64.msi文件。 双击go1.20.2.windows-amd64.msi&#xff0c;点击"Next"&#xff0c;然后勾选同…

Linux——进程信号1

信号和信号量是俩个东西&#xff0c;俩者无关系。 信号 信号本质是一种通知机制&#xff0c;用户or操作系统通过发送一定的信号&#xff0c;通知进程&#xff0c;某些事件已经发送&#xff0c;让进程进行后续处理。 结合进程&#xff0c;信号结论&#xff1a; 进程要处理信号&a…

【Windows线程开发】线程基础

本篇文章来带领大家了解Windows线程&#xff0c;了解线程的基本概念&#xff0c;了解线程的创建方式&#xff0c;以及一些简单的线程操作。 文章目录 一.线程基本概念二.创建线程三.线程实例&#xff08;单线程&#xff0c;多线程&#xff09;单线程执行多线程执行 四.挂起&am…

ElasticSeach 集成 springboot

声明是ElasticSearch? ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c; 基于RESTful web接口。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xff0c;是 当前流行的企业级搜索引擎…

大数据 | (五)通过Sqoop实现从MySQL导入数据到HDFS

知识目录 一、前言二、导入前的准备2.1 Hadoop集群搭建2.2 Hadoop启停脚本 三、docker安装MySQL四、安装Sqoop4.1 Sqoop准备4.2 Sqoop连接Mysql数据测试 五、导入MySQL数据到hdfs5.1 准备MySQL数据5.2 导入数据 六、Sqoop现状七、结语 一、前言 各位CSDN的朋友们大家好&#x…

5.11组会衍生总结:train/eval/BN、CNN与特征图、极大似然与EM、方差n与n-1(有偏估计/无偏估计)

目录组会问题:1.关于模型的train/eval与batchnorm1-1.理论1-2.实际运用(包含loss反向传播)2.CNN详解,特征图是什么CNN处理过程特征图(也叫通道)(num_features)总结(包含CNN图片的规律分析):3.极大似然估计与EM最大期望4.方差的n与n-1(有偏估计与无偏估计) 组会问题:…

企业文化和品牌文化是两回事

商业通常谈两类文化&#xff1a;企业文化&#xff0c;品牌文化 1&#xff09;组织内部的文化 2&#xff09;品牌以产品为依托&#xff0c;给消费群体营造的文化 “积极稳定”的文化氛围打造是个慢活 企业文化&#xff0c;既要挂在墙上&#xff0c;又要挂在嘴上&#xff0c;最终…

二叉查找树和平衡二叉树

二叉查找树 下面是一张数据库的表,有两列,分别是 Col1 和 Col2 我们来查找一下col289的这行数据,SQL语句如下: select * from a where col2 87没有用索引时执行上面的查询 , 数据从磁盘一条一条拿来对比最终找到结果&#xff0c;如果数据表很大,数据又在表尾的话,需要花费非…

Open3D点云数据处理(一):VSCode配置python,并安装open3d教程

文章目录 1 python下载与安装1.1 python下载1.2 python安装1.3 验证python是否安装成功 2 VSCode下载与安装2.1 下载2.2 安装2.3 安装汉化插件2.4 vscode安装python扩展2.5 编写一个简单的python程序并运行2.6 在外部终端中打印运行结果2.7 测试代码&#xff1a;使用python画一…

常用的网页设计工具,有哪些比较推荐

网页设计并不容易&#xff0c;易于使用的网页设计工具更难找到。随着网络的快速发展&#xff0c;网站迅速崛起&#xff0c;网页设计也很流行。本文收集了7款易于使用的网页设计工具&#xff0c;每一种近年来都受到网页设计师的广泛欢迎&#xff0c;以确保实用和易于使用。我希望…

背包九讲(dp问题详解)

一、01背包问题 首先了解一下题目&#xff1a; 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。…

Java中的抽象类介绍

Java中的抽象类介绍 抽象类可以包含普通类的成员&#xff0c;它可以包含普通的属性、方法和内部类等成员。这些成员既可以被抽象类的子类继承和使用&#xff0c;也可以被抽象类自身使用。抽象类中的非抽象方法必须要有具体实现&#xff0c;否则无法通过编译。抽象类中也可以拥…

Leetcode2379. 得到 K 个黑块的最少涂色次数

Every day a Leetcode 题目来源&#xff1a;2379. 得到 K 个黑块的最少涂色次数 解法1&#xff1a;滑动窗口 首先题目给出一个下标从 0 开始长度为 n 的字符串 blocks&#xff0c;其中 blocks[i] 是 ‘W’ 或者 ‘B’ &#xff0c;分别表示白色块要么是黑色块。 现在我们可…

抗体偶联药物都有哪些?(详细名单)

抗体偶联药物ADC简介 抗体-药物偶联物或ADC是一类生物制药药物&#xff0c;设计用于治疗癌症的靶向疗法。与化学疗法不同&#xff0c;ADC 旨在靶向并杀死肿瘤细胞&#xff0c;同时保留健康细胞。截至 2023 年5月&#xff0c;约有 433 家制药公司正在开发 ADC。 ADC 是由与具有…

SPI基础

SPI硬件接口 SPI协议使用3条总线以及片选线。3条总线分别是SCK、MOSI、MISO&#xff0c;片选线为SS(NSS、CS) SPI基础属性 主从模式&#xff1a;主机模式&#xff0c;从机模式 通讯频率&#xff1a;不定&#xff0c;根据设备速率确定 数据位数&#xff1a;4位、7位&#xff…