虚拟dom应用
vdom如何应用,核心api是什么
1、介绍snabbdom(开源社区用的多,vue2用的是他)
首先回顾下之前的vdom格式
真实的dom
<body> <ul id="list"> <li class="item">item 1</li> <li class="item">item 2</li> </ul> </body>
js模拟的dom
{ tag: 'ul', attrs: { id: 'list' }, children:[{ tag: 'li', attrs: { className: 'item' }, children: ['item 1'] },{ tag: 'li', attrs: { className: 'item'}, children:['item 2'] }] }
用js模拟的体量非常小。
看snabbdom里面的介绍。一个h函数,一个patch函数,就是vdom最主要的api。看h函数传的是什么。
第一个是标签div,标签对应的id #container,标签对应的class,two,classes。
第二个参数是,这个标签绑定了一个事件,函数叫someFn。
第三个是个数组,数组又是h函数,传入标签,属性,文本
第一次渲染是全部渲染到浏览器中,第二次渲染,数据源有所改变,根据改变重新生成一个newVnode,这个时候再patch。这个时候patch的时候,会进行一个对比,这个对比是只找出需要更新的那部分来更新
上面例子的模拟
<!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 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> var snabbdom = window.snabbdom; // 定义patch var patch = snabbdom.init([ snabbdom_class, snabbdom_props, snabbdom_style, snabbdom_eventlisteners ]) // 定义h var h = snabbdom.h; var container = document.getElementById('container'); // 生成vnode var vnode = h('ul#list', {}, [ h('li.item', {}, 'item 1'), h('li.item', {}, 'item 2') ]) patch(container, vnode); //模拟改变 var btnChange = document.getElementById('btn-change'); btnChange.addEventListener('click', function(){ var newVnode = h('ul#list', {}, [ h('li.item', {}, 'item 1'), h('li.item', {}, 'item b'), h('li.item', {}, 'item 3') ]); patch(vnode, newVnode); }) </script> </body> </html>
item1没有渲染,item b, item3闪烁了
2、重做之前的demo
<!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 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> var snabbdom = window.snabbdom; // 定义patch var patch = snabbdom.init([ snabbdom_class, snabbdom_props, snabbdom_style, snabbdom_eventlisteners ]) // 定义h var h = snabbdom.h; // 将该数据展示成一个表格。然后随便修改一个信息,表格也跟着修改 var data = [{ name: '张三', age: '20', address: '北京' },{ name: '李四', age: '21', address: '上海' },{ name: '王五', age: '22', address: '广州' }]; data.unshift({ name: '姓名', age: '年龄', address: '地址' }); var container = document.getElementById('container'); var btnChange = document.getElementById('btn-change'); // 渲染函数 var vnode; function render(data) { var newVnode = h('table',{}, data.map(function(item){ var tds = []; for (i in item){ if(item.hasOwnProperty(i)){ tds.push(h('td', {}, item[i]+'')) } } return h('tr',{}, tds); })); if (vnode) { // re-render patch(vnode, newVnode); } else { // 初次渲染 patch(container, newVnode); } vnode = newVnode; } render(data); btnChange.addEventListener('click', function(){ data[1].age = 30; data[2].address = '深圳'; // re-render render(data); }) </script> </body> </html>
再查看dom,不再是整个table渲染。就只更新改变的dom。
3、核心api
h('<标签名>', {...属性}, [...子元素])
h('<标签名>', {...属性}, '...')
patch(container, vnode)
patch(vnode, newVnode)