1.什么是虚拟DOM
- 用JS模拟DOM结构
- DOM变化的对比,放在JS层来做
- 提高重绘性能
2.模拟DOM表示形式
// 真实dom<ul id='list'><li class='item'>Item 1</li><li class='item'>Item 2</li><ul>// 虚拟dom{tag:'ul',attrs:{id:'list'},children:[{tag:'li',attrs:{className:'item'},children:['Item1']},{tag:'li',attrs:{className:'item'}children:['Item 2']}]}
3.创建DOM遇到的问题
我们来看一段代码
<body><ul id="wrap"></ul><button id="btn">改变</button></body><script>const person = [{name: "xiao ming",age: 25,},{name: "xiao zhang",age: 23,},];const btn = document.getElementById("btn");const wrap = document.getElementById("wrap");btn.addEventListener("click",function(){person[0].name = 'xiao li'render(person)})function render(params) {wrap.innerHTML = ''params.forEach((item) => {let cell = document.createElement("li");cell.innerHTML = `${item.name}-${item.age}`;wrap.appendChild(cell);});}render(person);</script>
当我们点击按钮时,我们改变了xiao ming的名称,但是dom帮我们把整个div的结构都重新渲染了一遍。如果我们在一个很大的工程中重复的做类似的操作,就会使我们的项目运行的很卡。所以就此引出了虚拟DOM的概念,我们只关心改变的那个DOM其他的不用去管。
我们来看一个创建div的操作。
<script>var div = document.createElement('div')var item,result = ''for(item in div){result += ' | ' + item ;}console.log(result)</script>

从上图中可以看出,我们每一次创建DOM都会创建出这么多属性来,如果多次创建,可以想象浏览器的性能。
- DOM操作是“昂贵”的,js运行的效率高
- 尽量减少DOM操作,而不是“推到重来”
- 项目越复杂,影响就越严重
- vdom即可解决这个问题
- 将DOM对比操作放在js层,提高效率
4.虚拟DOM案例
这里我们借助了一个虚拟dom的库snabbdom https://github.com/snabbdom/snabbdom
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>vdom</title><style>li {list-style: none;}</style></head><body><div id="container"></div><button id="btn-change">change</button><script src="https://cdn.bootcdn.net/ajax/libs/snabbdom/0.7.4/snabbdom.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/snabbdom/0.7.4/snabbdom-class.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/snabbdom/0.7.4/snabbdom-props.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/snabbdom/0.7.4/snabbdom-style.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/snabbdom/0.7.4/snabbdom-eventlisteners.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/snabbdom/0.7.4/h.js"></script><script>var snabbdom = window.snabbdom;var patch = snabbdom.init([snabbdom_class,snabbdom_props,snabbdom_style,snabbdom_eventlisteners,]);var h = snabbdom.h;var container = document.getElementById("container");var vnode = h("ul#list", {}, [h("li.item", {}, "Item 1"),h("li.item", {}, "Item 2"),]);patch(container, vnode);const btn = document.getElementById("btn-change");btn.addEventListener("click", function () {var newvnode = h("ul#list", {}, [h("li.item", {}, "Item 1"),h("li.item", {}, "Item 3"),h("li.item", {}, "Item 4"),]);patch(vnode, newvnode);});</script></body></html>
核心API:h函数、patch函数
打开浏览器运行一下案例,可以发现DOM不是整块重新渲染,它只是对修改的模块进行了重新渲染。
5.虚拟DOM和真实DOM更新数据操作对比
原始操作DOM:注销旧 DOM -> 数据 + 模板 => 新的一套HTML 代码 -> 挂载新 DOM
使用虚拟DOM:数据 + 模板 = 虚拟 DOM -> diff 新旧两套虚拟 DOM 的差异,得到补丁集 -> 把“补丁”打到真实 DOM 上
6.React中使用Key的作用
- 组件的DOM结构是相对稳定
- 类型相同的兄弟节点可以被唯一标识
- 算法复杂度O(n)
