vdom
全名 virtual dom,虚拟dom,简称vdom
定义
- 用js模拟dom结构
- Dom变化的对比,放在js层来处理
好处
- 提高重绘性能
- DOM操作比较占内存,将dom操作放在js层,可以提高效率性能
vdom-snabbdom
实现vdom的插件,可以在bootcdn.cn中下载(代码中有引入)
核心API
h(‘标签名’, {…属性…}, […子元素…]);----子元素有多个,再使用 h(…)嵌套
h(‘标签名’, {…属性…}, ‘标签的text’)
// html写法
<ul id="ulList">
<li>我是li</li>
</ul>
// 虚拟dom-snabbdom写法
h('ul#ulList',{},[
h('li',{},'我是li')
])
初次渲染
patch(container,vnode); // container真实存在的空dom节点
再次渲染,只渲染数据改变部分
path(vnode, newVnode); //newVnode变更的数据源
代码示例
需求:实现按钮点击,更改列表数据
*vdom只修改改变的数据,无改变的数据,dom不变
*点击btn时,可以展开dom结构,可以看到那些节点变更了
<!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>Vdom</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:"21",
address:"北京"
},
{
name:"张三",
age:"21",
address:"北京"
},
{
name:"张三",
age:"21",
address:"北京"
}
];
// 表头也放在data
data.unshift({
name:"姓名",
age:"年龄",
address:"地址"
})
var container = document.getElementById("container");
// 生成vnode
var vnode
function render(data){
var newVnode = h("table", {}, data.map(function(item){
var tds = [];
var i;
for(i in item){
// 判断i是不是自有属性,非原型属性
if(item.hasOwnProperty(i)){
// item[i]+"" 表示转换为字符串
tds.push(h("td", {}, item[i] + ""))
}
}
return h("tr", {}, tds)
}));
if (vnode) {
// 改变
patch(vnode, newVnode);
} else {
// 初次渲染
patch(container, newVnode);
}
// 赋值
vnode = newVnode;
}
// 初次渲染
render(data);
// btn点击事件
document.getElementById("btn-change").addEventListener("click",function(){
data[1].age = 30;
data[2].address = "深圳";
render(data);
})
</script>
</body>
</html>
附带github介绍(看完上面的例子,这个就很容易看懂了)
var snabbdom = require('snabbdom');
// 定义patch
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
var container = document.getElementById('container');
/*
解释
div id-container,有两个class-two,classes,
有一个点击事件someFn
第一个子节点span, 设置加粗样式,text是"This is bold"
第二个子节点是一个字符串
第三个子节点是a标签,有个href属性,指向"/foo",a的text是'I\'ll take you places!'
*/
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!')
]);
// 初次渲染:Patch into empty DOM element – this modifies the DOM as a side effect
patch(container, 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!')
]);
// 二次渲染:Second `patch` invocation
patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state