vue3从精通到入门3:patch函数源码实现方式

Vue3中的patch函数是Vue渲染系统的核心部分,它负责比较新旧虚拟DOM(VNode)节点,并根据比较结果更新实际的DOM:

先了解下patch函数源码,再进行对其中的解析:

function patch(  n1: VNode | null,  // 旧虚拟DOMn2: VNode,  // 新的虚拟DOMcontainer: HostNode,  anchor: ?HostNode = null,  parentComponent: ?Component = null,  parentSuspense: ?SuspenseBoundary = null,  isSVG: boolean = false,  optimized: boolean = false  
): VNode {  // ...  const { type, ref, shapeFlag } = n2;  switch (type) {  case Text:  // 处理文本节点  processText(n1, n2, container, anchor)break;  case Comment:  // 处理注释节点  processCommentNode(n1, n2, container, anchor) break;  case Static:  // 处理静态节点  if (n1 == null) {mountStaticNode(n2, container, anchor, namespace)} else if (__DEV__) {patchStaticNode(n1, n2, container, namespace)}  break;  case Fragment:  // 处理 Fragment 节点  processFragment(n1,n2,container,anchor,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,) break;  default:  // 处理元素或组件节点  if (shapeFlag & ShapeFlags.ELEMENT) {  // ... 处理元素节点 ...  processElement(n1,n2,container,anchor,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,)} else if (shapeFlag & ShapeFlags.COMPONENT) {  // ... 处理组件节点 ...  processComponent(n1,n2,container,anchor,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,)}  else if (shapeFlag & ShapeFlags.TELEPORT) {;(type as typeof TeleportImpl).process(n1 as TeleportVNode,n2 as TeleportVNode,container,anchor,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,internals,)} else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {;(type as typeof SuspenseImpl).process(n1,n2,container,anchor,parentComponent,parentSuspense,namespace,slotScopeIds,optimized,internals,)} // ...  }  // ... 其他逻辑,如处理子节点、引用、挂载等 ...  
}

以下我们以简化版解析:

1:processText处理文本节点:

processText 函数的主要作用是更新或创建文本节点。它的工作原理相对简单,因为它不涉及复杂的子节点或属性比较。

以下是 processText 函数的一个简化解析:

function processText(n1: VNodeText | null, n2: VNodeText, container: HostNode) {  if (n1 == null) {  // 如果旧节点为空(即第一次渲染文本),则创建新的文本节点  container.appendChild(createText(n2.text));  } else {  // 如果旧节点存在,则比较新旧文本内容  const el = n1.el as Text;  if (n1.text !== n2.text) {  // 如果文本内容不同,则更新文本节点的内容  el.textContent = n2.text;  }  }  
}

在这个简化的 processText 函数中:

  • n1 是旧文本节点(VNodeText 类型),n2 是新文本节点。
  • container 是文本节点应该被附加到的父 DOM 元素。

2:  processCommentNode处理注释节点:

注释节点在虚拟 DOM 中主要用于标记某些特殊的位置或状态,但它们并不直接映射到真实的 DOM 注释节点。在 Vue 3 中,注释节点主要用于内部优化和特定功能的实现,例如用于标记 v-if 指令的条件分支或插槽的边界。

processCommentNode 函数的主要任务是处理这些注释节点,确保它们在渲染过程中被正确处理。下面是该函数的一个简化解析:

function processCommentNode(  n1: VNodeComment | null,  n2: VNodeComment,  container: HostNode  
) {  // 如果旧注释节点不存在,创建新的注释节点  if (n1 == null) {  container.appendChild(createComment(n2.text));  } else {  // 如果旧注释节点存在,且新旧注释内容不同,更新注释内容  const el = n1.el as Comment;  if (n1.text !== n2.text) {  el.textContent = n2.text;  }  }  
}

在这个简化的 processCommentNode 函数中:

  • n1 是旧注释节点(如果存在的话),n2 是新注释节点。
  • container 是注释节点应该被附加到的父 DOM 元素。

3:  mountStaticNode:

静态节点是指那些在渲染过程中不会改变的节点。Vue 3 在编译阶段能够识别出这些节点,并在运行时跳过对它们的比较和更新,从而提高性能。mountStaticNode 函数的主要任务是将静态节点挂载到实际的 DOM 中。

下面是 mountStaticNode 函数的一个简化解析:

function mountStaticNode(node: VNodeStatic, container: HostNode) {  // 创建静态节点的 DOM 元素  const el = (node.el = createStaticNode(node));  // 将创建的 DOM 元素挂载到父容器中  container.appendChild(el);  
}

 在这个简化的 mountStaticNode 函数中:

  • node 是一个静态节点(VNodeStatic 类型)。
  • container 是静态节点应该被附加到的父 DOM 元素。

4:  patchStaticNode:

patchStaticNode 函数的主要任务是确保静态节点在更新过程中保持静态,并且只在必要时才进行 DOM 操作。这通常意味着,如果静态节点在父节点中的位置没有改变,并且它自身也没有改变,那么 patchStaticNode 将不会执行任何 DOM 操作。

下面是一个简化的 patchStaticNode 函数解析:

function patchStaticNode(n1: VNodeStatic | null, n2: VNodeStatic, container: HostNode) {  // 如果旧节点不存在,则创建新的静态节点  if (n1 == null) {  mountStaticNode(n2, container);  } else {  // 如果新旧节点是同一个引用(即没有变化),则不需要进行任何操作  if (n1 === n2) {  return;  }  // 检查静态节点的 key 是否发生变化,如果发生变化,则需要进行特殊处理  if (n1.key !== n2.key) {  // 这里可能需要进行更复杂的逻辑处理,比如移动节点等  } else {  // 如果只是静态节点的内容属性发生变化,但不需要更新 DOM,则忽略这些变化  // ...(其他属性比较逻辑)  }  // 在某些情况下,即使节点是静态的,也可能需要更新其子节点  // 因此,这里可能需要递归调用 patch 函数来处理子节点  }  
}

在这个简化的 patchStaticNode 函数中:

  • n1 是旧静态节点(如果存在的话),n2 是新静态节点。
  • container 是静态节点应该被附加到的父 DOM 元素。

5:  processFragment:

在解析 processFragment 函数之前,我们需要了解 Fragment 在 Vue 3 中的用途。Fragment 允许组件返回一个数组,其中每个数组项都是一个根节点。这在某些情况下很有用,比如当你需要渲染一个列表项的同时又需要渲染一些其他的元素。

下面是一个简化的 processFragment 函数的解析,注意,实际的源码可能更复杂并包含更多的优化和边界情况处理。

function processFragment(  n1: Fragment,  n2: Fragment,  container: HostNode,  anchor: ?HostNode,  parentComponent: ?Component,  parentSuspense: ?SuspenseBoundary,  isSVG: boolean,  optimized: boolean  
) {  const { patchFlag, dynamicChildren, children } = n2;  if (patchFlag > 0) {  // 如果有 patchFlag,可能表示有特殊的优化标志  // 根据不同的 patchFlag 执行相应的逻辑  // ...  } else if (!optimized) {  // 如果不是优化模式,直接递归处理每个子节点  for (let i = 0; i < children.length; i++) {  const nextChild = (children[i] = optimized  ? cloneIfMounted(children[i])  : normalizeVNode(children[i]));  patch(  n1 ? n1.children[i] : null,  nextChild,  container,  null,  parentComponent,  parentSuspense,  isSVG,  optimized  );  }  }  // 处理动态子节点的情况  if (dynamicChildren) {  // ...  // 这里处理动态添加或移除的子节点  }  // 如果有锚点,则使用锚点将新节点附加到容器中  if (anchor) {  // ...  // 将新节点附加到锚点之前  }  
}

在上面的简化代码中,processFragment 函数接收新旧两个 Fragment 类型的 VNode,以及其他必要的参数。它首先检查新节点的 patchFlag 属性,该属性用于标识节点是否有特殊的更新策略。

  • 如果有特殊的 patchFlag,它会执行相应的优化逻辑。
  • 如果没有 patchFlag 或者在非优化模式下,函数会遍历新 Fragment 的每个子节点,并递归调用 patch 函数来更新或创建这些子节点。

此外,processFragment 还会处理动态子节点的情况,这通常涉及添加或移除子节点,并更新 DOM 以反映这些变化。

最后,如果有锚点(anchor),函数会使用锚点来将新创建的节点附加到容器中。这确保了新节点被放置在正确的位置。

6:  processElement:

processElement 函数的主要任务是确保元素节点在更新过程中保持正确的状态,并更新其属性、子节点等。

下面是一个简化的 processElement 函数解析:

function processElement(  n1: VNode | null,  n2: VNodeElement,  container: HostNode,  anchor: ?HostNode,  isSVG: boolean  
) {  if (n1 == null) {  // 如果旧元素节点不存在,则创建新的元素节点  mountElement(n2, container, anchor, isSVG);  } else {  // 如果旧元素节点存在,则进行更新操作  // 比较元素类型,如果不一致,则进行替换操作  if (n1.type !== n2.type) {  replaceElement(n2, n1, container, anchor, isSVG);  } else {  // 元素类型一致,更新元素的属性和子节点  updateElement(n1, n2, isSVG);  }  }  
}

在这个简化的 processElement 函数中:

  • n1 是旧元素节点(如果存在的话),n2 是新元素节点。
  • container 是元素节点应该被附加到的父 DOM 元素。
  • anchor 是一个可选的锚点节点,用于确定新元素应该被插入到哪个位置。
  • isSVG 是一个布尔值,指示元素是否属于 SVG 命名空间。

 7:  processComponent:

processComponent 函数的主要任务是确保组件实例在更新过程中保持正确的状态,并处理组件的挂载、更新或卸载。

下面是一个简化的 processComponent 函数解析:

function processComponent(  n1: VNodeComponent | null,  n2: VNodeComponent,  container: HostNode,  anchor: ?HostNode,  parentComponent: ComponentInternalInstance | null,  parentSuspense: SuspenseBoundary | null,  isSVG: boolean  
) {  if (n1 == null) {  // 如果旧组件节点不存在,则创建并挂载新组件  mountComponent(n2, container, anchor, parentComponent, parentSuspense, isSVG);  } else {  const instance = (n2.component = n1.component);  // 如果新旧组件是同一个引用,则进行更新操作  if (shouldUpdateComponent(n1, n2, parentComponent, optimized)) {  // 更新组件的 props 和其他选项  updateComponent(n1, n2, optimized);  } else {  // 如果不需要更新组件,则标记组件为不需要再次渲染  n2.component.shouldKeepAlive = true;  }  // 处理组件的子节点  const nextTree = renderComponentRoot(instance);  patch(n1.subTree, nextTree, container, null, parentComponent, parentSuspense, isSVG);  }  
}

在这个简化的 processComponent 函数中:

  • n1 是旧组件节点(如果存在的话),n2 是新组件节点。
  • container 是组件应该被附加到的父 DOM 元素。
  • anchor 是一个可选的锚点节点,用于确定新组件应该被插入到哪个位置。
  • parentComponent 是父组件实例,用于处理嵌套组件的情况。
  • parentSuspense 是与组件相关的 Suspense 边界实例,用于处理异步组件的加载状态。
  • isSVG 指示组件是否属于 SVG 命名空间。

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

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

相关文章

车载以太网AVB交换机 TSN交换机 时间敏感网络 6端口 百兆 SW100TSN

SW100 TSN时间敏感网络AVB交换机 为6端口百兆车载以太网交换机&#xff0c;其中包含5通道100BASE-T1泰科MATEnet接口和1个通道100/1000BASE-T标准以太网(RJ45接口)&#xff0c;可以实现纳米级时间同步&#xff0c;车载以太网多通道交换&#xff0c;Bypass数据采集和监控等功能&…

代码格式上对齐的方法

昨天看到课程老师在sourceinsight中的操作&#xff0c;他不到两秒就把每行缩进字符数不同的代码行给统一对齐了。 我觉得这个很有用&#xff0c;虽然只是一个操作问题&#xff0c;而非技术问题。后来查了网络&#xff0c;记录一下这个方法。 比如有下面每行缩进不一样的代码&…

亲身体验!人工智能对话无障碍 —— BRClient 使用指南

01 概述 BRClient 这个名字来源于“Bedrock Client”的简称&#xff0c;寓意是为用户提供一个坚实的基础。BRClient 作为一个开源的桌面应用&#xff0c;为用户提供了友好的图形界面&#xff0c;让每个人都能够轻松访问和使用 Claude 3 的强大功能。用户可以自定义 Claude 3 的…

Vue.js 模板语法

Vue.js 使用了基于 HTML 的模板语法&#xff0c;允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。 Vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统。 结合响应系统&#xff0c;在应用状态改变时&#xff0c; Vue 能够智能地计算出重新…

Web APIs知识点讲解(阶段三)

DOM- 节点操作 一.节点操作 1.DOM节点 目标&#xff1a;能说出DOM节点的类型 DOM节点 DOM树里每一个内容都称之为节点 节点类型 元素节点 所有的标签 比如 body、 div html 是根节点 属性节点 所有的属性 比如 href 文本节点 所有的文本 document树&#xff1a; 总结&…

docker - 删除TAG为<none>的镜像

1.查看所有标记为 none 的镜像 docker images -f "danglingtrue"2. 获取镜像id docker images -f "danglingtrue" -q3、移除所有标记为 none 的镜像 docker rmi $(docker images -f "danglingtrue" -q)无法解决&#xff1a; 直接使用 docke…

Wireshark 抓包

启动时选择一个有信号的网卡双击打开&#xff0c;或者在 捕获选择里打开选择网卡。 然后输出下面的规则就可以抓到报文了。 最上面的三条是建立连接时的三次握手&#xff0c; 下面是发送数据hello 对应两条数据 最下面的4条是断时的4次挥手

Si24R2F+2.4GHz ISM 频段低功耗无线集成嵌入式发射基带无线

Si24R2F在原有Si24R2F的基础上&#xff1a;优化了射频性能、增加NTC测温、增加自动唤醒间隔、优化了蓝牙性能。在固定资产管理、冷链物流和牛羊畜牧业标签市场更具竞争力。 在原有SI24R2E做白卡/校徽的群体&#xff0c;在新的卡片机应用&#xff0c;更加推荐用SI24R2F&#xff…

[串联] MySQL 存储原理 B+树

InnoDB 是一种兼顾高可靠性和高性能的通用存储引擎&#xff0c;在 MySQL 5.5 之后&#xff0c;InnoDB 是默认的 MySQL 存储引擎。 InnoDB 对每张表在磁盘中的存储以 xxx.ibd 后缀结尾&#xff0c;innoDB 引擎的每张表都会对应这样一个表空间文件&#xff0c;用来存储该表的表结…

AXI-Stream——草稿版

参考自哔站&#xff1a;FPGA IP之AXI4-Lite AXI4-Stream_哔哩哔哩_bilibili 信号 传输层级从小到大 包(----------transfer--transfer--------)------delay--------包(----------transfer--transfer--------) TKEEP和TSTRB共同决定了是哪种数据流

Cocos游戏开发中的动态切割图片

点击上方亿元程序员+关注和★星标 引言 Cocos游戏开发中的动态切割图片 近日,由于笔者发现了另外一个非常有趣的画线切割小游戏,沉迷于夺回秋雅无法自拔,导致断更了一周多。(尊嘟假嘟) 言归正传,游戏体验过之后,非常感兴趣这个游戏中的切割效果是如何实现的呢? 今天…

Bean对象拷贝工具封装

在平时后端开发的过程中&#xff0c;经常要把对象封装成DTO,VO对象&#xff0c;来与前端进行交互 下面就是自己封装的对象拷贝工具&#xff1a; public class BeanCopyUtils {private BeanCopyUtils() {}public static <V> V copyBean(Object source,Class<V> cl…

【剑指offer】顺时针打印矩阵

题目链接 acwing leetcode 题目描述 输入一个矩阵&#xff0c;按照从外向里以顺时针的顺序依次打印出每一个数字。 数据范围矩阵中元素数量 [0,400]。 输入&#xff1a; [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 输出&#xff1a;[1,2,3,4,8,12,11,10,9,5,6,7] 解题 …

C语言动态分配数组

指针方式 可以使用指针&#xff0c;并在需要时通过malloc函数动态分配内存。下面是一个示例&#xff1a; #include <stdio.h> #include <stdlib.h>// 定义包含动态数组的结构体 struct DynamicArray {int size;int *array; };// 初始化结构体及动态数组 void ini…

【AutoML】一个用于图像、文本、时间序列和表格数据的AutoML

一个用于图像、文本、时间序列和表格数据的AutoML AutoGluon介绍安装AutoGluon快速上手 参考资料 AutoGluon自动化机器学习任务&#xff0c;使您能够在应用程序中轻松实现强大的预测性能。只需几行代码就可以训练和部署有关图像&#xff0c;文本&#xff0c;时间序列和表格数据…

记录在项目中引用本地的npm包

1、先把需要的包下载下来&#xff0c;以Photo Sphere Viewer 为引用的npm包、项目以shpereRepo为例子 git clone https://github.com/mistic100/Photo-Sphere-Viewer2、拉下代码后修改之后执行 ./build.sh build.sh #!/usr/bin/env bashyarn run build targetDir"../sh…

c# 设置图片透明度

逐个像素进行Alpha值的设置&#xff0c;网上其他的代码不能处理有透明背景的图片&#xff0c;因此要对Alpha、R、G、B均为0的透明色进行特殊处理&#xff0c;不做转换。 private Bitmap SetImageOpacity(Image srcImage, int opacity){Bitmap pic new Bitmap(srcImage);for (i…

mysql安装及操作

一、Mysql 1.1 MySQL数据库介绍 1.1.1 什么是数据库DB&#xff1f; DB的全称是database&#xff0c;即数据库的意思。数据库实际上就是一个文件集合&#xff0c;是一个存储数据的仓库&#xff0c;数据库是按照特定的格式把数据存储起来&#xff0c;用户可以对存储的数据进行…

【pytest、playwright】allure报告生成视频和图片

目录 1、修改插件pytest_playwright 2、conftest.py配置 3、修改pytest.ini文件 4、运行case 5、注意事项 1、修改插件pytest_playwright pytest_playwright.py内容如下&#xff1a; # Copyright (c) Microsoft Corporation. # # Licensed under the Apache License, Ver…

公网部署ctfd+ctfd_whale问题解决

参考博客 赵师傅&#xff1a;https://www.zhaoj.in/read-6333.html/comment-page-1 docker swarm&#xff1a;https://www.jianshu.com/p/77c4c62d9afe ctfd动态靶场搭建 https://blog.csdn.net/Java_ZZZZZ/article/details/131510368 docker swarm 节点标记 注意需要用以…