Virtual DOM 系列二:核心API
为了更好的研究Virtual DOM,我选择了snabbdom来学习。相比Vue来说,snabbdom对于研究虚拟DOM更好,因为它里面没有其他干扰的东西,而且源码也比较少,因此研究起来更方便。
1. 初次体验虚拟DOM的魅力
首先我们先用snabbdom重写之前的例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="container"></div>
<button id="btn-change">change</button>
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script>
<!-- 引入snabbdom相关库 -->
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-class.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-props.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-style.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-eventlisteners.js"></script>
<script src="https://cdn.bootcss.com/snabbdom/0.7.3/h.js"></script>
<script type="text/javascript">
var snabbdom = window.snabbdom;
//init patch function
var patch = snabbdom.init([
snabbdom_class,
snabbdom_props,
snabbdom_style,
snabbdom_eventlisteners
]);
// 定义h函数
var h = snabbdom.h;
var container = document.getElementById('container');
var data = [{
name: "张三",
age: 24,
address: "深圳"
}, {
name: "张三",
age: 24,
address: "深圳"
}, {
name: "张三",
age: 24,
address: "深圳"
}];
var oldVnode;
function render(data) {
var vnode = h('ul#list', {}, data.map(function (item) {
return h('li', {}, item.name+' '+item.age+' '+item.address)
}))
if (!oldVnode) {
//初始化页面渲染
patch(container, vnode);
} else {
//对比原来的vnode和新生成的vnewnode,找出差异,只渲染修改的部分
patch(oldVnode, vnode);
}
oldVnode = vnode;
}
$('#btn-change').click(function () {
data[1].name = '李四';
data[2].name = '王五';
//修改后重新渲染
render(data);
})
render(data); //初始化页面渲染
</script>
</body>
</html>
点击change,发现只修改了有差异的地方。对比之前jquery清空整个div,性能上有很大提升,特别是在复杂应用上。

2. 实现原理
通过上面snabbdom的例子,我们发现有两个核心的API:
1. h函数(将真实dom映射成虚拟节点);
h('<html 标签名>',{属性},[children])//含有子节点的
h('<html 标签名>',{属性},'text'])//没有子节点,只有文本,如<p>this is VN</p>
2. patch函数(通过对比新旧虚拟节点,找出差异(diff算法),再把这些变化更新到真实dom中)
patch(container, vnode)//初次渲染
patch(oldVnode, newVnode); //re-render

浙公网安备 33010602011771号