【vue】虚拟dom的原理是什么?手写实现虚拟dom !

news2024/11/18 13:46:09

 1.虚拟dom的原理

虚拟 DOM 是对 DOM 的抽象,本质上就是用 JavaScript 对象来描述 DOM 结构。Vue.js 中关于虚拟 DOM 的实现主要进行了以下几个步骤:

1.生成虚拟 DOM:
   Vue.js 使用 `render` 函数来依据模板代码生成虚拟 DOM。在这个过程中,每一个 HTML 标签都将被转换成一个 VirtualNode 对象,这个对象会记录该标签的类型、属性、子节点等信息。

2. 对比新旧虚拟 DOM: 
   当数据发生变化时,Vue.js 会重新生成新的虚拟 DOM,然后与旧的虚拟 DOM 进行对比(这个过程称为 Diff)。通过 Diff 算法,Vue 可以精确找出两个虚拟 DOM 之间的区别。

3. 局部更新真实 DOM: 
   根据对比结果,Vue 会直接计算出最小需要更新的 DOM 部分,并将这些变化应用到真实的 DOM 上。这种思路能够最大程度地减少对 DOM 的操作,从而提升性能。


2.手写实现虚拟dom(VirtualNode) 

以下是使用 JavaScript 创建和操作虚拟 DOM 的简化版本例子:

// 创建虚拟 DOM 对象
function createElement(tag, props, children) {
  return {
    tag,
    props,
    children
  }
}


// 渲染虚拟 DOM 到真实环境
function render(vnode, container) {
    var el;
  
    // 创建节点
    // 针对文本节点进行特殊处理
    if (typeof vnode === 'string' || typeof vnode === 'number') {
        el = document.createTextNode(vnode);
    }
    else {
        el = document.createElement(vnode.tag);
      
        // 设置 DOM 属性
        for (var key in vnode.props) {
            el.setAttribute(key, vnode.props[key]);
        }
  
        // 如果有子节点,递归调用 render 函数
        if (vnode.children) {
            vnode.children.forEach(child => {
                render(child, el); // 注意这里使用 el 作为容器
            });
        }
    }
    
    // 将生成的真实 DOM 挂载到 container 上
    container.appendChild(el);
}

// 创建虚拟 DOM
const vnode = createElement('div', { id: 'app' }, [createElement('div', {}, ['Hello, Virtual DOM'])]);

// 渲染到真实 DOM
render(vnode, document.body);

小结:

以上代码主要展示了如何创建虚拟 DOM 对象,并实现虚拟 DOM 到真实 DOM 的渲染。在真实的 Vue.js 中,虚拟 DOM 的实现会更加复杂,包括 Diff 算法、批量异步更新等优化措施。


在上面的基础上,让我们更深入理解 Virtual DOM (虚拟 DOM) 的 diff 算法和 patch 过程。

这两个环节主要做的是比较新老虚拟 DOM 的差异,并找出最少的修改,应用这些修改到真实 DOM 上,以提高应用的性能。

还是用示例来解释:(ps:我的思路记录在了代码中的注释上)

// 更新函数,用于比较新旧虚拟节点(vnode)的差异,并将差异应用到实际的 DOM 元素上。
function updateElement(vnode, oldVnode) {

    // 如果旧节点和新节点相同,那么什么都不做。
    if (vnode === oldVnode) return;

    // 如果有新的文本内容,那么更新文本内容。
    if (vnode.text) {
        oldVnode.text = vnode.text;
    }

    // 更新节点属性
    // el 是新旧节点共享的真实DOM元素
    var el = oldVnode.el = vnode.el;

    // oldProps 是旧虚拟节点的属性集合
    var oldProps = oldVnode.props;
    // props 是新虚拟节点的属性集合
    var props = vnode.props;

    // 如果旧属性在新属性集合中不存在,那么在真实 DOM 上移除这个属性。
    for (var key in oldProps) {
        if (!props.hasOwnProperty(key)) {
            el.removeAttribute(key);
        }
    }

    // 对比新旧属性集合,如果不相等,那么在真实 DOM 上更新这个属性。
    for (var key in props) {
        if (props[key] !== oldProps[key]) {
            el.setAttribute(key, props[key]);
        }
    }

    // 比较和更新子节点,此处简化为重新渲染所有子节点
    // oldChildren 是旧虚拟节点的子节点集合
    var oldChildren = oldVnode.children || [];
    // children 是新虚拟节点的子节点集合
    var children = vnode.children || [];

    // 逐个对比更新子节点
    for (var i = 0; i < children.length || i < oldChildren.length; i++) {
        // 递归调用 render 函数来处理子节点的更新,这里假设 render 函数会处理子节点的渲染和更新
        render(children[i], el, oldChildren[i]);
    }
}

这个 updateElement 函数是一个非常简化的例子,它检查 vnode 与 oldVnode 的差异,并将这些差异应用到实际的 DOM 元素上。然后它递归处理子节点。请注意,这个函数并没有处理节点类型不同的情况,也没有实现 key 属性和列表渲染的优化,这些问题都是 Vue.js 的 diff 算法需要解决的。

在实际的 Vue.js 中,虚拟 DOM 的更新过程会更加优化和复杂。比如 patch 过程会将修改操作放入队列,并在下一个事件循环中执行,同时对连续的同样操作进行合并,以达到最高的性能。此外,Vue.js 的 diff 算法也会根据列表渲染的 key 属性,寻找新旧 vnode 列表中相同的部分,以达到最小化 DOM 操作的效果。而且,当组件重新渲染时,Vue.js 会通过静态节点标记,避免不必要的比较和渲染,以进一步提升性能。

ps: 关于diff算法以及其他内容将会在下一篇博客中编写。

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

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

相关文章

Ansible playbook详解

playbook是ansible用于配置&#xff0c;部署&#xff0c;和被管理被控节点的剧本 playbook常用的YMAL格式&#xff1a;&#xff08;文件名称以 .yml结尾&#xff09; 1、文件的第一行应该以 "---" (三个连字符)开始&#xff0c;表明YMAL文件的开始。    2、在同一…

颜值实力“C位出道”:起亚EV6综合实力究竟怎么样?

作为起亚电动化转型的标杆之作&#xff0c;起亚EV6已在全球赢得广泛赞誉&#xff0c;连续斩获“2022欧洲年度汽车”及“2023北美年度汽车”等多项国际大奖&#xff0c;其GT版本更是荣获“2023年度世界性能车”&#xff0c;这些荣誉不仅标志着其设计和技术的国际认可&#xff0c…

安全区域边界(设备和技术注解)

网络安全等级保护相关标准参考《GB/T 22239-2019 网络安全等级保护基本要求》和《GB/T 28448-2019 网络安全等级保护测评要求》 密码应用安全性相关标准参考《GB/T 39786-2021 信息系统密码应用基本要求》和《GM/T 0115-2021 信息系统密码应用测评要求》 1边界防护 1.1应保证跨…

数据结构与算法之美学习笔记:18 | 散列表(上):Word文档中的单词拼写检查功能是如何实现的?

目录 前言散列思想散列函数散列冲突解答开篇 前言 本节课程思维导图&#xff1a; Word 的单词拼写检查功能&#xff0c;虽然很小但却非常实用。你有没有想过&#xff0c;这个功能是如何实现的呢&#xff1f;其实啊&#xff0c;一点儿都不难。只要你学完今天的内容&#xff0c;…

DDD领域驱动设计模式结构图面向接口编程

DDD领域驱动设计模式结构图面向接口编程 9.资源库 在刚接触资源库(Repository)时&#xff0c;第一反应便是这就是个 DAO 层&#xff0c;访问数据库&#xff0c;然后吧啦吧啦&#xff0c;但是&#xff0c;当接触的越久&#xff0c;越发认识到第一反应是错的&#xff0c;资源库更…

HTML5学习系列之主结构

HTML5学习系列之主结构 前言HTML5主结构定义页眉定义导航定义主要区域定义文章块定义区块定义附栏定义页脚 具体使用总结 前言 学习记录 HTML5主结构 定义页眉 head表示页眉&#xff0c;用来表示标题栏&#xff0c;引导和导航作用的结构元素。 <header role"banner…

YTM32的循环冗余校验CRC外设模块详解

YTM32的循环冗余校验CRC外设模块详解 文章目录 YTM32的循环冗余校验CRC外设模块详解引言原理与机制CRC算法简介从CRC算法到CRC硬件外设 应用要点&#xff08;软件&#xff09;CRC16 用例CRC32 用例 总结参考文献 引言 在串行通信帧中&#xff0c;为了保证数据在传输过程中的完…

尝试使用php给pdf添加水印

在开发中增加pdf水印的功能是很常见的&#xff0c;经过实验发现这中间还是会有很多问题的。第一种模式&#xff0c;采用生成图片的方式把需要添加的内容保存成图片&#xff0c;再将图片加到pdf中间&#xff0c;这种方法略麻烦一些&#xff0c;不过可以解决中文乱码的问题&#…

【MySQL】库的相关操作 + 库的备份和还原

库的操作 前言正式开始创建数据库删除数据库编码集查看系统默认字符集以及校验规则字符集校验规则 所有支持的字符集和校验规则所有字符集所有校验规则 指明字符集和校验规则创建数据库相同的字符集用不同的校验规则读取会出现什么情况 alter修改数据库show create databasealt…

全国各区县平均降水月数据!多时间版本可查询

本周给大家推荐一些环境监测数据~ 今天分享的是全国平均降水数据~ 全国平均降水是指全国各个地区降水的平均值。这个值是通过收集和统计全国各地的降雨和降雪数据得出的。由于各地的气候条件和地形不同&#xff0c;因此全国平均降水并不是简单的平均数&#xff0c;而是根据各…

lora微调模版

lora微调模版 1、版一&#xff1a;使用peft包的lora微调&#xff08;1&#xff09;设置超参方式一&#xff1a;代码中设置&#xff08;便于debug&#xff09;方式二&#xff1a; .sh文件指定 &#xff08;2&#xff09;加载数据集I、对应的.jsonl或json文件, 原始格式为&#x…

【Linux】第十三站:进程状态

文章目录 一、进程状态1.运行状态2.阻塞状态3.挂起状态 二、具体Linux中的进程状态1.Linux中的状态2.R状态3.S状态4.D状态5.T、t状态6.X状态(dead)7.Z状态&#xff08;zombie&#xff09;8.僵尸进程总结9.孤儿进程总结 一、进程状态 在我们一般的操作系统学科中&#xff0c;它…

基于springboot实现家具商城管理系统项目【项目源码】

基于springboot实现家具商城系统演示 Java语言简介 Java是由SUN公司推出&#xff0c;该公司于2010年被oracle公司收购。Java本是印度尼西亚的一个叫做爪洼岛的英文名称&#xff0c;也因此得来java是一杯正冒着热气咖啡的标识。Java语言在移动互联网的大背景下具备了显著的优势…

Linux学习第41天:Linux SPI 驱动实验(二):乾坤大挪移

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 本章的思维导图如下&#xff1a; 二、I.MX6U SPI主机驱动分析 主机驱动一般都是由SOC厂商写好的。不作为重点需要掌握的内容。 三、SPI设备驱动编写流程 1、SP…

Unity中Shader的雾效

文章目录 前言一、Unity中的雾效在哪开启二、Unity中不同种类雾的区别1、线性雾2、指数雾1&#xff08;推荐用这个&#xff0c;兼具效果和性能&#xff09;3、指数雾2&#xff08;效果更真实&#xff0c;性能消耗多&#xff09; 三、在我们自己的Shader中实现判断&#xff0c;是…

Java常用类和基础API

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 本…

Spark SQL 每年的1月1日算当年的第一个自然周, 给出日期,计算是本年的第几周

一、问题 按每年的1月1日算当年的第一个自然周 (遇到跨年也不管&#xff0c;如果1月1日是周三&#xff0c;那么到1月5号&#xff08;周日&#xff09;算是本年的第一个自然周, 如果按周一是一周的第一天) 计算是本年的第几周&#xff0c;那么 spark sql 如何写 ? 二、分析 …

蓝桥杯 插入排序

插入排序的思想 插入排序是一种简单直观的排序算法&#xff0c;其基本思想是将待排序的元素逐个插入到已排序序列 的合适位置中&#xff0c;使得已排序序列逐渐扩大&#xff0c;从而逐步构建有序序列&#xff0c;最终得到完全有序的序 列。 它类似于我们打扑克牌时的排序方式&…

缅因州政府通知130万人MOVEit数据泄露事件

大家好&#xff0c;今天我要向大家通报一个令人震惊的消息&#xff1a;缅因州政府的系统遭到了入侵&#xff0c;黑客利用MOVEit文件传输工具的漏洞&#xff0c;获取了约130万人的个人信息&#xff0c;这几乎相当于该州的整个人口数量。 MOVEit攻击是Clop勒索软件团伙进行的一次…

数据结构(超详细讲解!!)第二十三节 树型结构

1.定义 树型结构是一类重要的非线性数据结构&#xff0c;是以分支关系定义的层次结构。是一种一对多的逻辑关系。 树型结构是结点之间有分支&#xff0c;并且具有层次关系的结构&#xff0c;它非常类似于自然界中的树。树结构在客观世界中是大量存在的&#xff0c;例如家谱、…