为什么会有vdom?
- DOM操作是“昂贵”的,js运行效率高
- 应尽量减少DOM操作,而不是“推倒重来”
- 项目越复杂,影响就越严重
- vdom可以解决这个问题
解决
- virtual dom, 虚拟DOM
- vdom就是用JS虚拟DOM结构
- 因为DOM操作非常“昂贵”
- 将DOM对比操作放在JS层,提高效率
vdom的使用
vdom指的是一类技术实现,能实现vdom的库有很多,这里拿snabbdom来举例。
<div id="container"></div>
<button id="btn-change">change</button>
//引入snabbdom 注意保持版本一致
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-class.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-props.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-style.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-event-listeners.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-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
//h(标签,属性样式,子元素);
var vnode = h('ul#list', {}, [
h('li.item', {}, 'Item 1');
h('li.item', {}, 'Item 2');
]);
patch(container, vnode); //将vnode虚拟的dom结构渲染到container中
document.getElementById('btn-change').addEventListener('click',function(){
//生成newVnode
var newVnode = h('ul#list', {}, [
h('li.item', {}, 'Item 1');
h('li.item', {}, 'Item B');
h('li.item', {}, 'Item 3');
]);
patch(vnode, newVnode); //将新旧虚拟dom进行对比,找出差异,对差异进行重新渲染
});
</script>
<div id="container"></div>
<button id="btn-change">change</button>
//引入snabbdom 注意保持版本一致
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-class.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-props.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-style.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-event-listeners.js"></script>
<script src="https://cdn.boocss.com/snabbdom/0.7.1/snabbdom-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:'18',
address:'北京'
},
{
name:'钱二',
age:'19',
address:'上海'
},
{
name:'孙三',
age:'20',
address:'广州'
}
];
//把表头也放在data中
data.unshift({
name:'姓名',
age:'年龄',
address:'地址'
});
var container = document.getElementById('container');
//渲染函数
function render(data){
var newVnode = h('table', {},data.map(function(item){
var tds = [];
var i;
for(i in item){
if (item.hasOwnProty(i)) {
tds.push(h('td', {}, item[i] + ''));
}
}
return h('tr, {} tds');
}));
if (vnode) {
//re-render
patch(vnode, newVnode);
} else {
//初次渲染
patch(container, newVnode);
}
//存储当前vnode结果
vnode = newVnode;
}
//初次渲染
render(data);
var btnChange = document.getElementById('btn-change')
btnChange.addEventListener('click',function(){
data[1].age = 30;
data[2].address = '深圳';
//re-render
render('data');
});
</script>
snabbdom核心API
h函数:生成node节点
patch函数:将节点渲染到容器中,有两个用法
- h(‘标签名’,{属性},[子元素]) // 多个子元素(数组形式)
- h(‘标签名’,{属性},‘字符串’) // 子元素是一个人文本节点
- patch(container,vnode) //将虚拟dom渲染到容器中
- patch(vnode,newVnode) //将新旧虚拟dom进行比较,再将差异部分重新渲染
vdom为何使用diff算法
- DOM操作是"昂贵"的,因此尽量减少DOM操作
- 找出本次DOM必须更新的节点来更新,其他的不更新,这个"找出"的过程,就需要diff算法
diff算法
- 是linux的基础命令
- vdom中应用diff算法是为了找出需要更新的节点
- diff实现:patch(container,vnode) , patch(vnode,newVnode)
- 核心逻辑:createElement和updateChildren