Open yizihan opened 6 years ago
DOM操作很慢,操作DOM后会触发浏览器的重排和重绘。
虚拟DOM通过JS模拟DOM结构,来对真实DOM发生的变化保持追踪。
当数据改变时,新生成的Virtual DOM会与旧的Virtual DOM进行对比,通过Diff算法找到区别,这些操作都是在快速的JS中完成的,最后对实际DOM进行最小的DOM操作来完成效果。
// DOM <div id='parent'> <span class="child">item1</span> </div> // Virtual DOM const dom = { tagName: 'div', props: { id: 'parent' }, children: [ {tagName: 'span', props: {class: 'child'}, children: ['item1']} ] }
将Virtual DOM渲染成DOM
Element.prototype.render = function() { // 根据tagName构建真实DOM var el = document.createElement(this.tagName) var props = this.props // 遍历虚拟DOM中的属性 for (var propName in props) { // 获得属性值 var propValue = props[propName] // 为真实DOM添加属性 el.setAttribute(propName, propValue) } var children = this.children || [] // 遍历子元素 children.forEach(function(child) { var childEl = (child instanceof Element) // 如果还是标签元素,则继续渲染 ? child.render() // 文档元素 : document.createTextNode(child) el.appendChild(childEl) }) // 返回所有渲染后的真实DOM return el }
snabbdom 是轻量的 Virtual DOM 实现,代码量少,模块化,结构清晰。
snabbdom 主要的接口有:
示例
// 引入依赖 <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-class.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-props.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-style.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-eventlisteners.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/h.js"></script> // 初始化snabbdom 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 data = [{name: 'aaa', age: 20}, {name: 'bbb', age: 30}]; var vnode // 将数据渲染为虚拟DOM函数 function render(data) { // 将后台给的data对象调用h(),返回一个虚拟DOM对象 // re-render时会重新生成,然后和之前生成的Diff 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] + '')) } } // 在table里面添加tr,tr里面包含所有的td及td包含的内容 return h('tr', {}, tds) })) if (vnode) { // re-render渲染通道 patch(vnode, newVnode) } else { // 初次渲染通道 patch(container, newVnode) } // 替换vnode的值 vnode = newVnode } // 执行初次渲染 render(data) var btn = document.getElementById('btn') btn.addEventListener('click', function() { var data = [{name: 'aaa', age: 20}, {name: 'ccc', age: 40}]; // 只渲染发生修改的地方!!! render(data); })
参考文章:解析 snabbdom 源码
比较innerHTML和Virtual DOM的重绘
Virtual DOM只会对同一层级的元素进行对比,不会跨层级比较。
设置key值可以最大化的利用节点(可以复用节点)。
// 1.构建虚拟DOM var Tree = el('div', {'id': 'container'}, [ el('h1', {style: 'color:blue'}, ['simple virtual dom']) ]) // 2.通过虚拟DOM渲染真正的DOM var root = tree.render() document.body.appendChild(root) // 3.生成新的虚拟DOM var newTree = el('div', {'di': 'container'}, [ el('h1', {style: 'color: red'}, ['simple virtual dom']) ]) // 4.比较两个虚拟DOM的不同,记录差异,将不同的地方都放在patches数组 var pathces = diff(Tree, newTree) // 5.在真正的DOM元素上应用变更 patch(root, patches)
虚拟DOM
DOM操作很慢,操作DOM后会触发浏览器的重排和重绘。
虚拟DOM通过JS模拟DOM结构,来对真实DOM发生的变化保持追踪。
当数据改变时,新生成的Virtual DOM会与旧的Virtual DOM进行对比,通过Diff算法找到区别,这些操作都是在快速的JS中完成的,最后对实际DOM进行最小的DOM操作来完成效果。
将Virtual DOM渲染成DOM
snabbdom (2018-03-17)
snabbdom 是轻量的 Virtual DOM 实现,代码量少,模块化,结构清晰。
snabbdom 主要的接口有:
示例
参考文章:解析 snabbdom 源码
比较innerHTML和Virtual DOM的重绘
DOM Diff
Virtual DOM只会对同一层级的元素进行对比,不会跨层级比较。
设置key值可以最大化的利用节点(可以复用节点)。