什么是虚拟DOM
在浏览器中,虚拟DOM是指用js对象来表示页面上的元素,并提供了操作DOM对象的API。
在框架中,虚拟DOM是指用js对象来模拟 页面上DOM和DOM嵌套。
在 React 中,render 执行的结果得到的并不是真正的 DOM 节点,结果仅仅是轻量级的 JavaScript 对象,我们称之为 virtual DOM。

虚拟DOM的本质
一个虚拟DOM(元素)是一个一般的js对象,准确的说是一个对象树(倒立的);虚拟DOM保存了真实DOM的层次关系和一些基本属性,与真实DOM一一对应;如果只是更新虚拟DOM,页面是不会重绘的。
虚拟DOM的目的
实现页面上的元素高效更新
虚拟DOM基本原理
用JS对象树表示DOM树的结构;然后用这个树构建一个真正的DOM树插到文档当中;当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异;把差异应用到真实DOM树上,视图就更新了。
比如页面上有一个表格,需求现在要更改表格中的其中某一项,需求只需要更改表格中要更改的那一项,其余的不改变,这样性能才是做好的,简单的来说就是按需更新。
虚拟DOM的实现过程
DOM树概念
简单来说就是由文档及文档中的所有的元素(标签)组成的一个树形结构图,叫树状图(DOM树)

react中创建虚拟DOM
- 原生js创建(基本不使用)
React.createElement('h1', {id:'myTitle'}, title)
- 使用jsx创建(下一篇具体讲解)
简单流程
- 通过原生js生成DOM
// 原生js创建(基本不使用)
let virtualDom1 = createElement('ul', {class: 'list'}, [
createElement('li', {class: 'item'}, ['a']),
createElement('li', {class: 'item'}, ['b']),
createElement('li', {class: 'item'}, ['c']),
])
// jsx语法创建
<div className="confirm">
<Mask onClick={()=> cancel('123')}/>
<div className='cf_box'>
<div className='cf_feild'>
<h6>{title || '提示'}<Icon type="close" onClick={()=> cancel('123')} /></h6>
</div>
</div>
</div>
let patchs = diff(virtualDom1, virtualDom2);
- 渲染到页面上
// 原生js
let el = render(virtualDom);
renderDom(el, window.root);
// jsx 直接写在render函数即可
render() {
const {onclick} = this.props;
return (
<div className='mask_box' onClick={()=> onclick && onclick()}>
</div>
)
}
- 更新时,使用diff算法比较,改变虚拟DOM
- 按需更新
React diff算法

- tree diff

注意点
只会对相同颜色方框内的 DOM 节点进行比较,即同一个父节点下的所有子节点。
当发现节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。
- component diff

注意点
当 component D 改变为 component G 时,即使这两个 component 结构相似,一旦 React 判断 D 和 G 是不同类型的组件,就不会比较二者的结构,而是直接删除 component D,重新创建 component G 以及其子节点。
- element diff

在进行组件对比的时候,如果两个组件类型相同,则需要进行元素级别的对比,这叫做Element Diff。
注意点
新老集合所包含的节点,如下图所示,新老集合进行 diff 差异化对比,通过 key 发现新老集合中的节点都是相同的节点,因此无需进行节点删除和创建,只需要将老集合中节点的位置进行移动,更新为新集合中节点的位置,此时 React 给出的 diff 结果为:B、D 不做任何操作,A、C 进行移动操作,即可。