vue diff算法与虚拟dom知识整理(8) 手写patch实现简易版的节点第一次上dom树

news2024/11/26 0:57:12

上一文 我们整理了一下 patch 函数的整体过程
我不知道大家有没有保留我们之前学手写H函数时的那个案例 我们要将index.jsi还原成这样
参考代码如下

import h from "./snabbdom/h";

const dom1 = h("div",{
  props: {class: "dom"}
},"文本测试");

const dom2 = h("div",{
  props: {class: "dom"}
},[
  h("div",{},"java"),
  h("div",{},"html"),
  h("div",{},[
    h("div",{},"react"),
    h("div",{},"css")
  ])
]);

const dom3 = h("div",{
  props: {class: "dom"}
},h("div",{},"java"));

console.log(dom1);
console.log(dom2);
console.log(dom3);

只是说 我们还是要用自己写的那个h函数
但这次 我们真的是要把虚拟节点上树了

我们在案例的 src下的snabbdom 下创建一个 patch.js
在这里插入图片描述
可能有人会问 我们看到的不是init的吗?
没错 在源码中 patch 是init的一部分 init其实就是组装了各种模型 但我们只需要做一个简易版的patch 做一下虚拟节点上树 和 比较最小化更新就好了

然后 我们在案例 src下的snabbdom 下创建一个createElement.js

然后 我们先写patch.js的代码 便于大家理解
patch.js 参考代码如下

import vnode from "./vnode";
import createElement from "./createElement";

export default function(oldVnode, newVnode) {
    //先判断oldVnode  第一个参数 是一个虚拟节点  还是一个真实的dom节点
    if(!oldVnode.sel) {
        //如果oldVnode中 拿不到sel  表示这是一个真实的节点  因为虚拟节点中  sel 代表标签类型选择器
        //那么 我们就要将虚拟节点转为真实的节点
        //这里 我们通过vnode  将真实节点转为真实节点
        /*
            第一个参数sel  标签选择器  我们通过tagName.toLowerCase() 获取dom节点的 标签类型
            第二个参数data  标签的数据  dom老节点肯定是没有的  我们直接{}
            第三个参数  children  子集集合   我们这里肯定是没有的  直接 []  或者  undefined
            第四个参数  text  文本内容 我们这里 没有直接undefined
            最后一个   elm  他上树的节点   我们直接给他自己  oldVnode
        */  
        oldVnode = vnode(oldVnode.tagName.toLowerCase(),{},[],undefined,oldVnode);
    }

    //判断  oldVnode  和  newVnode 是不是同一个节点
    //判断的条件是  sel  标签选择器  和  key  元素表示是否都相同
    if(oldVnode.sel == newVnode.sel && oldVnode.key == newVnode.key) {

    } else {
        //else 走进来 表示两者并不是同一个节点
        //那就执行 暴力拆除旧的  插入新的
        createElement(newVnode, oldVnode.elm);
    }
}

这里 我们就做了上文说的两件事 第一件 判断第一个节点是不是一个虚拟节点 如果不是 通过 vnode 转为虚拟节点 这里 我注释写的还是比较全的大家可以看一下

然后 判断 两个虚拟节点是不是一样的 如果是 那我们这篇文章先放在这 我妈后面再去补这块逻辑
然后 如果不是同一个节点
我们走进createElement 首先 我解释一下这两个参数 首先 第一个 是patch接到的第二个参数 就是要渲染上去的虚拟节点 然后 第二个 是 oldVnode.elm
那我们 上面调用vnode 最后一个参数对应elm 是不是 他这个elm存的就是 真实的dom节点本身啊

所以 第二个参数 我们是将这个存在elm中的真实的dom节点传进去了

好了 然后我们来写createElement.js的逻辑

//创建节点
//函数接收两个参数  vnode  需要插入的虚拟节点   pivot  需要插入到哪一个元素之前
export default function(vnode, pivot) {
    //先用虚拟节点的sel  标签名选择器 创建一个真实的dom节点
    let domNode = document.createElement(vnode.sel);
    //如果  能判断到虚拟节点下的 text 文本属性  而且 拿不到children子节点  或者 children  子节点 没有长度
    if(vnode.text && (!vnode.children || !vnode.children.length)){
        //这个条件达到  表示  他的内容是一个文章  没有子节点
        //直接将虚拟节点的 text 文本内容 通过innerText写入到新节点中
        domNode.innerText = vnode.text;

        /*
            通过pivot上树   通过pivot.parentNode  获取到  pivot的父元素 放在insertBefore前 这个大家可以了解一下  insertBefore的概念
            然后将刚刚通过虚拟节点创建的节点  通过insertBefore上树  惨遭就是pivot
        */
        pivot.parentNode.insertBefore(domNode, pivot);
    }

}

我们这里接到了这两个参数 第一个 要插入的虚拟节点 第二个 对照插入位置的一个真实dom节点

进来 我们先通过createElement 将虚拟节点 创建成一个真正的dom孤儿节点
createElement(标签名) 这里需要标签名 而我们虚拟节点的sel中是不是正好就是标签名?

然后 我们先判断 如果 这个节点的文本不是空的 而且 他没有子节点
那就 直接通过innerText 将虚拟节点中的文本属性text写进去

这样 我们参照插入的节点 和要插入的孤儿节点都好了 就直接执行
insertBefore上树

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

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

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

const vnode = h("h1", {}, "你好");

patch( container, vnode)

这里 我们先获取了页面上的 container元素 然后通过h函数创建了一个 h1虚拟节点
然后我们通过自己写的patch进行上树操作

运行代码如下
在这里插入图片描述
可以看到 方法虽然写的捡漏了一些 但中心思想没变 节点它还是上去了

然后 我们将src下 index.js 代码改一下 我们试试多层嵌套

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

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

const vnode = h("ul", {}, [
  h("li", {}, "1A"),
  h("li", {}, "2B"),
  h("li", {}, "3C"),
  h("li", {}, "4D"),
]);

patch( container, vnode)

在这里插入图片描述
可以看到 这样 我们的节点直接就没了

这个 我们就需要利用递归的方式去处理一下了 下一文 我们再继续说

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

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

相关文章

Qt QJson 使用

文章目录 1. 简介2. 简单实例3. 结果 1. 简介 QJson 是一个用于 Qt 应用程序的 JSON 解析和生成库。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,具有良好的可读性和可扩展性,常用于 Web 应用程序中。QJson 将 …

Python通过natcap.invest库调用InVEST模型批处理数据(Carbon Storage and Sequestration模块)

InVEST(Integrated Valuation of Ecosystem Servicesand Tradeoffs)生态系统服务和权衡的综合评估模型,旨在通过模拟不同土地覆被情景下生态系统物质量和价值量的变化。它提供了多种生态系统服务功能评估,包括了淡水生态系统评估、…

Liunx压缩命令 - gz

gz命令详解及使用 Linux中gz命令的全称是gzip,它是一种常用的压缩程序,可将文件或目录压缩为.gz格式,以节省存储空间,同时也可以通过解压缩操作重新获取原始文件掌握 gzip 命令,可以帮助我们更加高效地进行文件压缩与…

视频编码测试平台CodecWar

​在视频编码的研究和开发中,我们经常需要对编码器的性能进行比较,一般的做法是构建一个数据集,然后将两个编码器在同一个配置上(LD,RA,AI等)使用不同参数(CQP下一般为4个QP值)编码,…

Py之pymc:pymc的简介、安装、使用方法之详细攻略

Py之pymc:pymc的简介、安装、使用方法之详细攻略 目录 pymc的简介 pymc的安装 pymc的使用方法 1、时序性任务 (1)、使用 Euler-Maruyama 方案推断 SDE 的参数 pymc的简介 PyMC(以前称为PyMC3)是一个专注于高级马尔科夫链蒙特卡洛&#x…

⑤电子产品拆解分析-人体感应灯

⑤电子产品拆解分析-人体感应灯 一、功能介绍二、电路分析以及器件作用三、原理图复现与学习 一、功能介绍 ①感应人体活动亮灯20S;②Micro-USB进行锂电池充电; 二、电路分析以及器件作用 三、原理图复现与学习 R1为下拉电阻,防止上电因芯…

功率放大器的选型原则和方法是什么

功率放大器是一种能够将低电平信号放大到足够高的电平以驱动负载的电子器件。在各种电子设备中,功率放大器被广泛应用,如音响系统、电视广播、汽车音响、射频通信等。因此,正确选型功率放大器非常重要,可以提高设备的性能和可靠性…

Web3的应用及发展

Web3兼具去中心化和交互性,打造了一个全新的互联网模式。在其中,用户可以绕过中介直接交互。dApp用户无需许可即可访问金融工具,以点对点的方式交易加密资产,获得参数型保险理赔,通过NFT交易可验证所有权的数字艺术品&…

[网鼎杯 2020 青龙组]bang 复现

一.前言 在NSSCTF练习安卓逆向,第一次遇到安卓脱壳题 大佬的题解只有一句话"frida-dexdump一把嗦" 听起来容易做起来难,还遇到了安卓虚拟机的玄学bug,折磨了我很久,好在最终使用真机成功dump并得到flag 题目来源:[网鼎杯 2020 青龙组]bang 如果直接用jadx打开会发现…

Vector - CAPL - CANoe DBC消息相关自动化_01

目录 getFirstCANdbFilename -- 获取数据库的文件名 代码示例 getFirstCANdbName -- 获取数据库的名称 代码示例 getSignalName -- 获取报文的信号名称 getMessageAttrInt -- 获取信号属性值 代码示例 getFirstCANdbFilename -- 获取数据库的文件名 功能:找出…

Python: 结合多进程和 Asyncio 以提高性能

动动发财的小手,点个赞吧! 简介 多亏了 GIL,使用多个线程来执行 CPU 密集型任务从来都不是一种选择。随着多核 CPU 的普及,Python 提供了一种多处理解决方案来执行 CPU 密集型任务。但是直到现在,直接使用多进程相关的…

Pytrack 函数整理

1 distance 1.1 add_edge_lengths pytrack.graph.distance.add_edge_lengths(G, precision3) 将每条边的长度加到图里面去 1.1.1 主要参数 G路网图precision每一条边长度,保持几位小数 1.2 enlarge_bbox pytrack.graph.distance.enlarge_bbox(north, south, …

僵尸进程的避免 守护进程的创建 线程的创建,阻塞,数据传递 5.15

父子进程相关知识&#xff1a; 1.子进程结束时&#xff0c;系统 会立即自动刷新行缓存 2.手动结束进程&#xff1a; exit() exit(int status)&#xff1a;结束当前调用的进程&#xff0c;自动刷新缓存 标准库函数 头文件&#xff1a;#include <stdlib.h> _exit() …

压缩技术与常见linux解压/压缩命令总结

文章目录 1 RAR1.1 参数介绍1.2 压缩/解压1.3 分卷压缩/解压 2 7-Zip2.1 常用参数2.2 使用2.3 分卷压缩/解压 3 解压/压缩命令 总结 1 RAR RAR是一种专利文件格式&#xff0c;用于数据的压缩打包。 提供了强力压缩、分卷、加密和自解压模块 官方网址&#xff1a;https://www…

公有云——阿里云ECS服务器(IaaS)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.了解云服务器的基础概念 1.云服务器的基础概念&#xff08;云服务器选择…

用IDEA写的第一个JavaWeb项目(保姆级)

任何事情只有0次和无数次&#xff0c;项目新建了第一个就有第二个 从第一次的略显青涩到后面的轻车熟路&#xff0c;区别就是第一次 ——Lungcen 在IDEA中新建一个web项目&#xff0c;有好几种方法。本人用的方法是通过maven构建工具来构建java项目的框架。对于web服务器的选择…

日志—加索引优化select

今天工作中遇到一个小问题&#xff0c;一个搜索接口&#xff0c;要加一个2个字段用于搜索 分析&#xff1a;这两个字段要在子表中去查询&#xff0c;查看原来mapper中的接口&#xff0c;已经连了N个子表&#xff0c;sql速度在10秒左右。 加上了新的子表&#xff0c;然后去试了…

悼念浩哥(左耳朵耗子),一个纯粹的技术人

上周末听闻浩哥的事了&#xff0c;期初还不信。在网上搜索消息&#xff0c;看来是真的。他才四十多岁&#xff0c;觉得非常可惜。很早就关注过浩哥&#xff0c;他是一位正直纯粹和爱分享的技术大牛。无论是技术分享还是人生感悟&#xff0c;或者是成长相关&#xff0c;都让我学…

展会直击 | 昂视精彩亮相CIBF2023深圳国际电池展

5月16日&#xff0c;CIBF2023深圳国际电池展在深圳国际会展中心&#xff08;宝安新馆&#xff09;正式开幕&#xff0c;昂视携2D视觉产品、3D视觉产品、锂电行业智能检测方案亮相9号馆T101-2展位&#xff0c;会场氛围火热&#xff0c;昂视展位人声鼎沸。 方案演示&#xff0c;助…

K8s进阶1——搭建K8s高可用集群

文章目录 一、资源清单二、系统初始化2.1 所有服务器配置2.2 master节点配置 三、nginxkeepalived3.1 主备机器上进行3.2 配置主节点3.3 配置备节点3.4 启动服务 四、部署etcd集群4.1 资源清单4.2 生成Etcd证书4.3 部署Etcd集群 五、安装Docker/kubeadm/kubelet5.1 安装docker5…