什么是虚拟Dom

一、前言

虚拟DOM概念随着react的诞生而诞生,由facebook提出,其卓越的性能很快得到广大开发者的认可;继react之后vue2.0也在其核心引入了虚拟DOM的概念,本文将以vue2.0使用的snabbdom入手,来介绍虚拟DOM的主要实现原理。

二、虚拟DOM

在开始介绍snabbdom之前我们想来想两个问题,

(1)什么是虚拟DOM?

vdom可以看作是一个使用javascript模拟了DOM结构的树形结构,这个树结构包含整个DOM结构的信息,如下图:

img img

可见左边的DOM结构,不论是标签名称还是标签的属性或标签的子集,都会对应在右边的树结构里。

(2)为什么要使用虚拟DOM?

之前使用原生js或者jquery写页面的时候会发现操作DOM是一件非常麻烦的一件事情,往往是DOM标签和js逻辑同时写在js文件里,数据交互时不时还要写很多的input隐藏域,如果没有好的代码规范的话会显得代码非常冗余混乱,耦合性高并且难以维护。

另外一方面在浏览器里一遍又一遍的渲染DOM是非常非常消耗性能的,常常会出现页面卡死的情况;所以尽量减少对DOM的操作成为了优化前端性能的必要手段,vdom就是将DOM的对比放在了js层,通过对比不同之处来选择新渲染DOM节点,从而提高渲染效率。

(3)vdom如何使用?

下面我将使用snabbdom的用法介绍一下vdom的使用。

三、snabbdom

要了解snabbdom的话有必要先去github上先了解下snabbdom: https://github.com/snabbdom/snabbdom

在这里看到官方给的一个example

img

这里可以看到列出来的两个主要的核心函数,即h()函数和patch()函数,我们先来看下h()函数:

h函数

img img

可以看到创建的虚拟DOM树里面的结构在左边的vnode里都有体现,所以现在看来我们的虚拟DOM结构树和snabbdom中的h()函数是完全可以对应起来的,可以通过一个方法将虚拟DOM结构转化成vnode;而上图中newVnode则指的是虚拟DOM树中的数据发生变化之后生成的vnode。

我们在回过头来看patch()函数

patch函数

patch函数的执行分为两个阶段,两次传递的参数都是两个

第一阶段为虚拟dom的第一次渲染,传递的两个参数分别是放真实DOM的container和生成的vnode,此时patch函数的作用是用来将初次生成的真实DOM结构挂载到指定的container上面。

第二阶段传递的两个参数分别为vnode和newVnode,此时patch函数的作用是使用diff算法对比两个参数的差异,进而更新参数变化的DOM节点;

可以发发现h函数和patch函数在cnabbdom中实现vdom到真实DOM的转化起到了至关重要的作用,那么还有一个很重要的环节,patch函数中是怎么样实现对比两个vnode从而实现对真实DOM的更新的呢,这里还要提一下snabbdom的另外一个核心算法,即diff算法。

diff算法

其实在我们日常开发中我们都在接触类似与diff算法的一些软件,比如svn可以看到当前代码和svn服务器上代码的不同之处,再如Beyond Compare这款软件也可以为我们指出两个对比文件的不同之处

但是此处是如何实现对vnode的对比的呢?参考以下代码:

 1 function updateChildren(vnode, newVnode) {      // 创建对比函数
 2     var children = vnode.children || []         
 3     var newChildren = newVnode.children || []
 4 
 5     children.forEach(function(childrenVnode, index) {
 6         var newChildVnode = newChildren[index]  // 首先拿到对应新的节点
 7         if (childrenVnode.tag === newChildVnode.tag) {    // 判断节点是否相同
 8             updateChilren(childrenVnode, newChildVnode)   // 如果相同执行递归,深度对比节点
 9         } else {
10             repleaseNode(childrenVnode, newChildVnode)    // 如果不同则将旧的节点替换成新的节点
11         }
12     })
13 }
14 
15 
16 function repleaseNode(vnode, newVnode) {    // 节点替换函数
17     var elem = vnode.elem
18     var newEle = createElement(newVnode)
19 }

[

此处简单的列举了一下diff算法的原理,以上是最简单的对比,更复杂的对比函数包括对节点的增删以及其它的节点逻辑就不一一赘述了,这里最重要的一部分就是递归的使用,才能将vnode进行深度对比。

四、小结

虚拟DOM在目前流行的几大框架中都作为核心的一部分使用,可见其性能的高效,本文只是简单的通过列举vue中使用的snabbdom库做一个简单的剖析,想要更深层次的理解vdom还有很长的路要走,本文如有不当之处,还劳烦路过大佬批评指出。

<think>首先,用户的问题是:“我想了解虚拟DOM树的概念 请问什么是虚拟DOM树”。我需要根据系统级指令用户可见层的要求来回答。 系统级指令: 1. 所有行内数学表达式使用 $...$ 格式。 2. 独立公式使用 $$...$$ 格式并单独成段。 3. LaTeX语法正确。 4. 使用中文回答。 5. 生成相关问题。 6. 回答中引用的段落末尾自然地添加引用标识,例如 [^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 - 参考站内引用(提供的引用内容)。 提供的引用: - [^1]: 理解虚拟dom虚拟 DOM是由一系列的 JavaScript 对象组成的树状结构,每个对象代表着一个DOM元素,包括元素的标签名、属性、子节点等信息。虚拟 DOM中的每个节点都是一个 JavaScript 对象,它们可以轻松地被创建、更新销毁,而不涉及到实际的DOM操作。将目标所需的 UI 通过数据结构“虚拟”地表示出来,保存在内存中,然后将真实的DOM与之保持同步 主要作用。 - [^2]: 什么是虚拟DOM。Virtual DOM虚拟DOM),是由普通的 JS 对象来描述DOM对象,因为不是真实的DOM对象,所以叫 Virtual DOM虚拟DOM就是使用一个虚拟DOM 树来描述真实的 DOM 树结构节点属性,通过比较新旧两颗虚拟 DOM 树的差异,最终只需要对修改的部分进行实际的 DOM 操作。 使用步骤: 虚拟DOM就是将当前页面的 DOM 树映射为一个 JavaScript 对象形式的虚拟 DOM。然后当应用程序状态发生改变时,根据新状态生成一个新的虚拟 DOM。比较新旧两个虚拟 DOM 的差异,得到需要进行修改的 DOM 元素。根据差异列表,对有修改的 DOM 元素进行实际的 DOM 操作,使浏览器重新渲染。 - [^3]: 什么是虚拟DOM?如何实现一个虚拟DOM?。虚拟DOM(Virtual DOM)是一个轻量级的JavaScript对象,它表示DOM树的结构。虚拟DOM是对真实DOM的一种抽象表示,旨在提高页面的更新性能。通过对虚拟DOM进行操作,再将变化应用到真实DOM,框架可以最小化直接操作真实DOM的开销,从而提高性能。 虚拟DOM的优势 高效的更新:通过diff算法比较新旧虚拟DOM,找出最小变化集,然后批量更新真实DOM,减少不必要的重绘重排。跨平台:虚拟DOM可以用同样的方式来描述不同平台(如浏览器服务器端)的UI结构。简单的编程模型:开发者可以用声明式编程方式描述UI,而不必关心具体的DOM操作细节。 - [^4]: 虚拟Dom的基本理解。虚拟 DOM 的实现原理主要包括以下 3 部分: 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;diff 算法— 比较两棵虚拟 DOM 树的差异;pach 算法— 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。 用户的问题是关于虚拟DOM树的概念,所以我需要从这些引用中提取关键点来构建一个清晰的解释。 回答结构: 1. 定义虚拟DOM树:用简单的中文解释什么是虚拟DOM树。 2. 核心概念:描述它如何工作,包括它的组成、目的优势。 3. 工作原理:简要说明创建、更新比较的过程。 4. 优势:列出主要好处。 5. 自然地引用引用的内容。 最后,生成相关问题。 确保使用中文回答。 由于没有数学表达式,我不需要担心LaTeX格式,但指令说“所有行内数学表达式”,所以如果提到数学相关,比如算法,但这里主要是描述性的,所以可能不需要。 现在,构建回答: - 开头:直接回答问题。 - 中间:逐步解释。 - 结尾:添加引用生成相关问题。 引用标识:在相关段落末尾添加,如 [^1]。 生成相关问题:基于主题,比如实现、优势、比较等。 最终输出: - 回答部分。 - §§相关问题§§ - 相关问题列表。</think>### 虚拟DOM树的概念 虚拟DOM树(Virtual DOM Tree)是一种用于优化网页渲染性能的技术,它通过JavaScript对象模拟真实DOM树的结构,从而避免直接操作高开销的真实DOM元素。简单来说,虚拟DOM树是真实DOM树的一个轻量级“副本”,由JavaScript对象组成,每个对象代表一个DOM元素(如标签名、属性、子节点等)。当应用程序状态变化时,框架(如ReactVue)会生成新的虚拟DOM树,并与旧的树进行比较(使用diff算法),找出最小差异,最后只更新真实DOM中必要的部分,而不是整个页面。这大大减少了浏览器的重绘(repaint)重排(reflow)操作,提升了性能[^1]。 #### 核心组成工作原理 1. **结构表示**:虚拟DOM树使用JavaScript对象来描述真实DOM树的结构。例如: - 一个真实DOM元素 `<div id="root"><p>Hello</p></div>` 会被映射为一个虚拟DOM对象: ```javascript { tag: 'div', props: { id: 'root' }, children: [ { tag: 'p', props: {}, children: ['Hello'] } ] } ``` 这种表示方式允许在内存中轻松创建修改,而不涉及实际DOM操作[^2]。 2. **更新流程**: - **生成新树**:当应用状态改变时(如用户交互),框架根据新数据生成一个新的虚拟DOM树。 - **比较差异(Diff算法)**:框架比较新旧两棵虚拟DOM树,找出节点属性或结构的变化(如新增、删除或更新节点)。diff算法高效地识别最小变化集,避免不必要的比较[^3]。 - **应用变化(Patch操作)**:基于差异列表,框架只对真实DOM进行局部更新(例如,只修改一个按钮的文本,而不是整个页面)。这确保了渲染过程高效且平滑[^4]。 3. **主要优势**: - **性能优化**:通过批量更新最小化DOM操作,减少浏览器重绘/重排的开销,特别适用于复杂UI应用[^3]。 - **跨平台兼容**:虚拟DOM树可以抽象表示不同平台的UI(如Web、移动端或服务器端渲染),提高代码复用性[^3]。 - **开发简化**:开发者只需关注UI状态(声明式编程),无需手动管理DOM细节,降低了错误风险[^1]。 #### 为什么需要虚拟DOM树? 在传统Web开发中,直接操作真实DOM(如通过JavaScript的 `document.getElementById()`)会导致频繁重绘,性能低下。虚拟DOM树作为中间层,将UI逻辑与渲染分离,使得更新更高效。例如,在React中,每次状态变化都会触发虚拟DOM树的重新生成比较,确保只有实际变化的部分被渲染[^2][^4]。 虚拟DOM树是现代前端框架的核心机制,通过抽象优化,显著提升了用户体验[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值