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)