简单总结一下,由于在浏览器端频繁操作 DOM 是非常耗性能的事情,为了避免这种情况,我们会使用 JS 来模拟 DOM 结构,同时,DOM 结构的变化也同样放在 JS 层操作(JS 是图灵完备语言),这就是为什么会存在 virtual DOM 的原因。 既然 DOM 结构需要用 JS 来进行模拟,那我们下面就举一个具体的例子看看究竟是如何进行模拟的呢?
var container = document.getElementById('container')
// 渲染函数 var vnode functionrender(data) { var newVnode = h('table', {}, data.map(function (item) { var tds = [] var i for (i in item) { if (item.hasOwnProperty(i)) { tds.push(h('td', {}, item[i] + '')) } } return h('tr', {}, tds) }))
上面的实现过程基本与 jQuery 的相类似,只不过引用了 snabbdom 中的函数,大家可以去浏览器中观察 DOM 的变化,看看与之前的有什么不同,不同的地方也恰恰就是 virtual DOM 存在的原因。 讲了 virtual DOM 是什么,也初步体验了 virtual DOM 的实现过程,接下来,我们继续去了解 virtual DOM 中的核心算法 —— diff 算法。
// patch(container, vnode); functioncreateElement(vnode) { var tag = vnode.tag // 'ul' var attrs = vnode.attrs || {} var children = vnode.children || [] if (!tag) { returnnull }
// 创建真实的 DOM 元素 var elem = document.createElement(tag) // 属性 var attrName for (attrName in attrs) { if (attrs.hasOwnProperty(attrName)) { // 给 elem 添加属性 elem.setAttribute(attrName, attrs[attrName]) } } // 子元素 children.forEach(function (childVnode) { // 给 elem 添加子元素 elem.appendChild(createElement(childVnode)) // 递归 })
functionreplaceNode(vnode, newVnode) { var elem = vnode.elem // 真实的 DOM 节点 var newElem = createElement(newVnode)
// 替换 }
上面的 createElement、updateChildren 仅仅是对 DOM 元素做了最简单的对比,就像本节开始提醒到的,我们现在在了解的阶段,无需去关注细节,把握大体实现流程即可。本文没有涉及到的内容,比如节点的新增和删除、节点的重新排序、节点的样式、属性、事件绑定等内容,如果有兴趣的同学可以自己下来慢慢研究。
以上就是 virtual DOM 与 diff 算法入门介绍的全部内容了,我们从为什么会有 virtual DOM 入手,介绍了它是什么以及如何应用,同时介绍了最核心的 diff 算法,希望对大家有所帮助。