目录

一、虚拟 DOM 的核心概念

二、虚拟 DOM 到真实 DOM 的流程

三、手写虚拟 DOM 到真实 DOM 的实现

1. 定义虚拟 DOM 的结构(VNode) 

 2. 创建虚拟 DOM 转真实 DOM 的函数

 3. 挂载虚拟 DOM 到页面

 4. 更新虚拟 DOM 的过程(Diff 算法简化版)

四、完整示例:虚拟 DOM 到真实 DOM 的生命周期

五、总结


一、虚拟 DOM 的核心概念

虚拟 DOM 是用 JavaScript 对象(VNode)模拟真实 DOM 结构的轻量级抽象。它的核心作用是:

  1. 减少直接操作真实 DOM 的次数:通过对比新旧虚拟 DOM 树的差异(Diff 算法),仅更新变化的部分。
  2. 声明式编程:开发者只需关注数据逻辑,无需手动操作 DOM。
  3. 跨平台能力:虚拟 DOM 可用于 Web、移动端(如 Weex)或服务端渲染(SSR)

 

二、虚拟 DOM 到真实 DOM 的流程

Vue 的渲染流程可分为以下步骤:

  1. 模板编译:将模板(<template>)编译为渲染函数(render function)。
  2. 生成虚拟 DOM 树:通过 render 函数返回一个虚拟 DOM 树(由 VNode 节点组成)。
  3. 首次挂载:将虚拟 DOM 树转化为真实 DOM 并渲染到页面。
  4. 数据更新:生成新的虚拟 DOM 树,与旧树进行 Diff 算法比较。
  5. 局部更新:将差异部分应用到真实 DOM 上(Patch 过程)。

三、手写虚拟 DOM 到真实 DOM 的实现

以下是一个简化版的实现示例,涵盖虚拟 DOM 的创建、挂载和更新过程。

1. 定义虚拟 DOM 的结构(VNode) 
// VNode 结构
const vnode = {tag: 'div',          // 标签名props: { id: 'app' }, // 属性children: [          // 子节点{tag: 'p',props: { class: 'text' },children: ['Hello, Vue!']}]
};
 2. 创建虚拟 DOM 转真实 DOM 的函数
// 将虚拟 DOM 转换为真实 DOM
function createDom(vnode) {const { tag, props, children } = vnode;const dom = document.createElement(tag); // 创建真实 DOM 元素// 设置属性if (props && typeof props === 'object') {updateProps(dom, props);}// 处理子节点if (Array.isArray(children)) {reconcileChildren(children, dom);}return dom;
}// 设置属性
function updateProps(dom, props) {for (const key in props) {if (key === 'style') {// 处理 style 属性for (const styleKey in props.style) {dom.style[styleKey] = props.style[styleKey];}} else {// 处理其他属性(id、class 等)dom[key] = props[key];}}
}// 递归处理子节点
function reconcileChildren(children, dom) {for (const child of children) {const childDom = createDom(child); // 递归创建子节点dom.appendChild(childDom);}
}

 

 3. 挂载虚拟 DOM 到页面
// 将虚拟 DOM 挂载到容器
function render(vnode, container) {const dom = createDom(vnode); // 生成真实 DOMcontainer.appendChild(dom);   // 挂载到页面
}// 示例:将虚拟 DOM 挂载到 #root 容器
const root = document.getElementById('root');
render(vnode, root);
 4. 更新虚拟 DOM 的过程(Diff 算法简化版)
// 比较新旧虚拟 DOM 树并更新真实 DOM
function patch(oldVnode, newVnode, parentDom) {// 如果节点类型不同,直接替换if (oldVnode.tag !== newVnode.tag) {parentDom.replaceChild(createDom(newVnode), oldVnode.elm);return;}// 获取真实 DOMconst elm = (newVnode.elm = oldVnode.elm);// 更新属性updateProps(elm, oldVnode.props, newVnode.props);// 递归比较子节点patchChildren(oldVnode.children, newVnode.children, elm);
}// 更新属性
function updateProps(dom, oldProps, newProps) {// 移除旧属性for (const key in oldProps) {if (!newProps[key]) {dom[key] = null;}}// 更新或新增属性for (const key in newProps) {if (key === 'style') {for (const styleKey in newProps.style) {dom.style[styleKey] = newProps.style[styleKey];}} else {dom[key] = newProps[key];}}
}// 递归比较子节点
function patchChildren(oldChildren, newChildren, parentDom) {// 简化版:逐个比较子节点const maxLength = Math.max(oldChildren.length, newChildren.length);for (let i = 0; i < maxLength; i++) {const oldChild = oldChildren[i];const newChild = newChildren[i];if (oldChild && newChild) {patch(oldChild, newChild, parentDom);} else if (newChild) {// 新增节点parentDom.appendChild(createDom(newChild));} else if (oldChild) {// 删除节点parentDom.removeChild(oldChild.elm);}}
}

四、完整示例:虚拟 DOM 到真实 DOM 的生命周期

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>手写 Vue 虚拟 DOM</title>
</head>
<body><div id="root"></div><script>// 1. 初始虚拟 DOMconst initialVnode = {tag: 'div',props: { id: 'app' },children: [{tag: 'p',props: { class: 'text' },children: ['Hello, Vue!']}]};// 2. 挂载初始虚拟 DOMconst root = document.getElementById('root');const initialDom = createDom(initialVnode);root.appendChild(initialDom);// 3. 模拟数据更新后的新虚拟 DOMconst newVnode = {tag: 'div',props: { id: 'app' },children: [{tag: 'p',props: { class: 'text updated' },children: ['Hello, Vue! Updated!']}]};// 4. 更新虚拟 DOM 到真实 DOMpatch(initialVnode, newVnode, root);</script>
</body>
</html>

五、总结

通过上述实现,我们可以看到 Vue 虚拟 DOM 的核心原理:

  1. 虚拟 DOM 是 JavaScript 对象:通过 createDom 函数将虚拟 DOM 转化为真实 DOM。
  2. Diff 算法是性能优化的关键:通过比较新旧虚拟 DOM 树的差异,仅更新变化的部分。
  3. 局部更新减少重排/重绘成本:避免了直接操作真实 DOM 的高昂代价。

在实际开发中,Vue 的虚拟 DOM 实现更为复杂(如处理组件、事件绑定等),但核心思想一致。掌握虚拟 DOM 的原理,不仅能帮助我们更好地理解 Vue 的运行机制,还能在性能优化和跨平台开发中游刃有余。

 

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

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

相关文章

jmm--volatile

指令重排基础概念 在现代处理器和编译器为了提高程序执行效率&#xff0c;会对指令进行优化&#xff0c;其中一种优化方式就是指令重排序。在单线程环境下&#xff0c;指令重排序不会影响最终执行结果&#xff0c;因为处理器和编译器会保证重排序后的执行结果与按照代码顺序执行…

【硬件开发】滤波电容的选择:原理、计算与多电压值应用实践

滤波电容的选择&#xff1a;原理、计算与多电压值应用实践 1. 引言 在现代电子系统中&#xff0c;稳定的电源供应是保证电路可靠运行的基础。然而&#xff0c;电源线上往往不可避免地存在各种噪声和纹波&#xff0c;这些干扰可能源自电源本身&#xff08;如整流后的脉动直流&…

【seismic unix数据生成-unif2】

Seismic Unix简介 Seismic Unix&#xff08;SU&#xff09;是由科罗拉多矿业学院&#xff08;Colorado School of Mines&#xff09;开发的开源地震数据处理软件包&#xff0c;专为地震勘探数据分析和研究设计。它提供了一系列命令行工具&#xff0c;支持从数据加载、处理到可…

【逆向思考 并集查找】P2391 白雪皑皑|省选-

本文涉及知识点 C并集查找 P2391 白雪皑皑 题目背景 “柴门闻犬吠&#xff0c;风雪夜归人”&#xff0c;冬天&#xff0c;不期而至。千里冰封&#xff0c;万里雪飘。空中刮起了鸭毛大雪。雪花纷纷&#xff0c;降落人间。 美能量星球&#xff08;pty 在 spore 上的一个殖民地…

一文讲清楚React中setState的使用方法和机制

文章目录 一文讲清楚React中setState的使用方法和机制1. setState是什么2. setState方法详解2.1 setState参数详解2.2 setState同步异步问题2.2.1 setState异步更新2.2.2 setState同步更新 一文讲清楚React中setState的使用方法和机制 1. setState是什么 React中&#xff0c;…

01_软件卓越之道:功能性与需求满足

引言 在软件的世界里&#xff0c;功能性是产品与用户之间的第一桥梁。一个软件即使拥有华丽的界面和极致的性能&#xff0c;如果不能解决用户的核心需求&#xff0c;也终将被市场淘汰。本文将深入探讨如何确保软件的功能性与用户需求完美契合。 1. 需求理解&#xff1a;从模糊…

StarRocks × Tableau 连接器完整使用指南 | 高效数据分析从连接开始

一、导语&#xff1a;为什么选择 StarRocks Tableau 连接器&#xff1f; 在当今数据驱动的商业环境中&#xff0c;企业不仅需要一个能够处理海量数据的高性能分析数据库&#xff0c;还需要一个直观、强大的可视化工具来解读数据背后的故事。StarRocks 作为新一代极速全场景 MP…

基于 SpringBoot+VueJS 助农生鲜销售系统设计与实现7000字论文实现

摘要本论文设计并实现了一个基于 SpringBoot 和 VueJS 的助农生鲜销售系统。系统采用前后端分离架构&#xff0c;前端使用 VueJS 框架实现用户界面&#xff0c;后端使用 SpringBoot 框架构建服务&#xff0c;通过 MyBatis 实现数据持久化。系统实现了农产品展示、在线购物、订单…

Pytest 测试发现机制详解:自动识别测试函数与模块

概述 在编写自动化测试时,如何让 Pytest 自动找到你的测试代码 是一个非常基础但重要的问题。Pytest 通过其强大的 测试发现(Test Discovery)机制,能够自动扫描项目目录、识别测试模块和测试函数,从而大大简化了测试流程。 本文将为你详细讲解 Pytest 的测试发现机制,包…

MySQL 时间日期函数

时间日期类型 MySQL中主要支持以下几种时间日期类型&#xff1a; DATE - 日期类型 格式&#xff1a;YYYY-MM-DD范围&#xff1a;1000-01-01 到 9999-12-31示例&#xff1a;2023-05-20 TIME - 时间类型 格式&#xff1a;HH:MM:SS范围&#xff1a;-838:59:59 到 838:59:59示例&…

408第三季part2 - 计算机网络 - 物理层

理解 这里有8个波形&#xff0c;每个波形代表一个马原&#xff0c;一个马原代表多个比特&#xff0c;这里3个比特 求波特率就直接2W 求比特率就要乘log2V 这块记两公式就行&#xff0c;一个下面一个上面 题目 4个相位加4种幅度就是有16种波形 这里无噪声就是奈奎斯特定理 这…

iOS 集成RN Installing glog (0.3.5)报错的解决方案

在集成执行RN bundle exec pod install 命令到Installing glog (0.3.5)时报错,报错信息如下: Installing glog (0.3.5) [!] /bin/bash -c set -e #!/bin/bash # Copyright (c) Facebook, Inc. and its affiliates. # # This source code is licensed under the MIT license …

【进阶篇-消息队列】——MQTT协议如何支持海量的在线IoT设备

目录 一、什么是IoT二、MQTT 和其他消息队列的传输协议有什么不同三、如何选择 MQTT 产品四、MQTT 集群如何支持海量在线的 IoT 设备五、总结本文来源:极客时间vip课程笔记 一、什么是IoT IoT,也就是物联网,物联网这个词儿,它的含义还不那么直观,但你看它的英文:IoT,也就…

Chat Model API

聊天模型API为开发人员提供了将人工智能聊天完成功能集成到应用程序中的能力。它利用预训练的语言模型&#xff0c;如GPT&#xff08;生成预训练转换器&#xff09;&#xff0c;以自然语言对用户输入生成类似人类的响应。 API通常通过向人工智能模型发送提示或部分对话来工作&…

【黑群晖】自组硬件/旧电脑nas改造(三)——使用Jellyfin创建家庭影音库

一、打开套件中心安装Jellyfin套件 如果找不到Jellyfin套件&#xff0c;需要手动添加三方套件源&#xff1a; 《群晖NAS必学技能&#xff1a;一键解锁三方套件源&#xff0c;PT下载影音播放全搞定&#xff01;》 二、配置Jellyfin 访问http://群晖IP:8096 进入Jellyfin初始化界…

泰山派编译debian报错 lb config: unrecognized option ‘--debootstrap-options‘

简介 最近在编译泰山派 编译buildroot系统正常&#xff0c;但是编译debian时总是报错说lb 找不到一些参数&#xff0c;如下图所示&#xff0c;应该当前的版本较低 不支持这些参数&#xff0c;我试了很多方法 升级次版本 但是提示的是最新的&#xff0c;最后经过一番搜索 在官方…

跨境证券交易系统合规升级白皮书:全链路微秒风控+开源替代,护航7月程序化交易新规落地

1 行业变革&#xff1a;四重驱动力重塑证券交易系统 当前全球证券行业正处于深刻变革期&#xff0c;跨境金融活动面临前所未有的机遇与挑战。今日央行开展的1310亿元7天期逆回购操作&#xff0c;以及国家外汇管理局向合格境内机构投资者(QDII)新增发放30.8亿美元投资额度等政策…

Node.js核心API(fs篇)

前言&#xff1a;在Node.js生态系统中&#xff0c;文件系统操作是后端开发不可或缺的一部分。fs模块作为Node.js核心API的重要组成部分&#xff0c;提供了与文件系统交互的能力&#xff0c;涵盖了从基础的文件读写到复杂的目录操作等功能。现代JavaScript开发中&#xff0c;处理…

HarmonyOS学习2---Stage模型

1、工程目录结构 1.1、入口 UIAbility 1.2、入口page 1.3、配置文件 1、配置文件 1&#xff09;应用级配置文件 --- app.json5 2&#xff09;模块级配置文件 --- module.json5 3、oh-package.json5 4、资源文件 1&#xff09;element目录 2&#xff09;media目录 3&#xff09…

【软件工程】软件复刻项目的完整流程指南

软件复刻项目的完整流程指南 第一章、概述 一、前期准备&#xff1a;明确目标与合规性 1. 法律风险评估 版权排查&#xff1a;确认目标软件的 UI 设计、代码、商标是否受保护&#xff08;如界面元素、核心算法是否申请专利&#xff09;。规避侵权&#xff1a;避免直接复制 …