虚拟dom的优势
1、提高性能
JS对象描述DOM相较于真实的DOM对象,内容上轻很多,如果直接对真实的DOM进行diff操作,会有大量额外的属性比对。
2、跨平台优势
虚拟DOM只是对内容的一个描述,通过不同的宿主环境,可以通过执行不同的渲染代码,生产出不同平台的内容。
vdom更新机制(diff算法)
Snabbdom源码地址 github.com/coconilu/Bl…
源码
var snabbdom = require('snabbdom'); // 引入库
// patch其实就是个snabbdom的初始化方法,后面一堆引入可以不关注
var patch = snabbdom.init([ // Init patch function with chosen modules
require('snabbdom/modules/class').default, // makes it easy to toggle classes
require('snabbdom/modules/props').default, // for setting properties on DOM elements
require('snabbdom/modules/style').default, // handles styling on elements with support for animations
require('snabbdom/modules/eventlisteners').default, // attaches event listeners
]);
// 引入h函数
var h = require('snabbdom/h').default; // helper function for creating vnodes
// 拿到一个dom元素
var container = document.getElementById('container');
// 利用h函数生成一个vnode
var vnode = h('div#container.two.classes', {on: {click: someFn}}, [
h('span', {style: {fontWeight: 'bold'}}, 'This is bold'),
' and this is just normal text',
h('a', {props: {href: '/foo'}}, 'I\'ll take you places!')
]);
// 下面这句相当于新建了一个vnode,把他与一个空dom进行对比,vnode替换空dom
// Patch into empty DOM element – this modifies the DOM as a side effect
patch(container, vnode);
// 新建一个vnode
var newVnode = h('div#container.two.classes', {on: {click: anotherEventHandler}}, [
h('span', {style: {fontWeight: 'normal', fontStyle: 'italic'}}, 'This is now italic type'),
' and this is still just normal text',
h('a', {props: {href: '/bar'}}, 'I\'ll take you places!')
]);
// 下面这句是说旧vnode和新vnode进行比对,如果新不同于旧,那么就用新的代替旧的。
// Second `patch` invocation
patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state
diff算法主要是由patch函数完成的。
return function patch (oldVnode: VNode | Element, vnode: VNode): VNode {
// 第一个参数是一个vnode或者dom,第二个参数是vnode
...
// 如果第一个参数不是 vnode
if (!isVnode(oldVnode)) {
// 创建一个空的vnode ,并且要继承这个DOM元素的属性
oldVnode = emptyNodeAt(oldVnode);
}
// 如果是相同的 vnode(key 和 sel(选择器)都相等)
if (sameVnode(oldVnode, vnode)) {
// 进行 vnode 对比
patchVnode(oldVnode, vnode, insertedVnodeQueue);
// 如果是不同的 vnode ,直接删掉旧的,重建新的
} else {
// 先获取父级dom
elm = oldVnode.elm!;
parent = api.parentNode(elm);
// 重建
createElm(vnode, insertedVnodeQueue);
// 父级不为空,就把重建的vnode挂在下面
if (parent !== null) {
api.insertBefore(parent, vnode.elm!, api.nextSibling(elm));
removeVnodes(parent, [oldVnode], 0, 0);
}
}
...
return vnode;
};
vue是源码直接作为模板引擎产生vdom,react把引擎交给用户自己,更灵活