virtual dom

VDom就是用JS虚拟创建的一个DOM对象,但并没有挂载到页面上,那他的作用是什么? 很简单,那就是个真实DOM做对比,对比两课DOM树的差别来进行局部更新,这样就不用重新渲染整个虚拟DOM树来进行更新,也符合了“数据驱动”的思想,避免了重绘和重排,提高了Web性能。

1.vue 的虚拟DOM 节点树构建过程

 

Vue 先将模板编译成render函数,渲染出虚拟 DOM ,然后再通过virtual DOM的diff方法来更新真实的DOM树。

这个过程中,还可以通过watcher监听“虚拟DOM”发生的变化并保持追踪;它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,及其子节点,通过这个过程,Vue 会自动保持页面的更新,开发者就可以高效的更新所有DOM节点。

2.Diff方法:仅在同级的vnode间做diff,递归地进行同级vnode的diff,最终实现整个DOM树的更新

实例来看下整个diff的过程(节点属性中不带key的情况):

首先从第一个节点开始比较,不管是oldCh还是newCh的起始或者终止节点都不存在sameVnode,同时节点属性中是不带key标记的,因此第一轮的diff完后,newChstartVnode被添加到oldStartVnode的前面,同时newStartIndex前移一位;

第二轮的diff中,满足sameVnode(oldStartVnode, newStartVnode),因此对这2个vnode进行diff,最后将patch打到oldStartVnode上,同时oldStartVnodenewStartIndex都向前移动一位

第三轮的diff中,满足sameVnode(oldEndVnode, newStartVnode),那么首先对oldEndVnodenewStartVnode进行diff,并对oldEndVnode进行patch,并完成oldEndVnode移位的操作,最后newStartIndex前移一位,oldStartVnode后移一位;

第五轮的diff中,同过程1;

遍历的过程结束后,newStartIdx > newEndIdx,说明此时oldCh存在多余的节点,那么最后就需要将这些多余的节点删除。

 

patch原理:

function patchElement(parent, newVNode, oldVNode, index = 0) {
if(!oldVNode) {
  parent.appendChild(newVNode.render())
} else if(!newVNode) {
  parent.removeChild(parent.childNodes[index])
} else if(newVNode.tag !== oldVNode.tag || newVNode.text !== oldVNode.text) {
  parent.replaceChild(newVNode.render(), parent.childNodes[index])
}  else {
for(let i = 0; i < newVNode.children.length || i < oldVNode.children.length; i++) {
  patchElement(parent.childNodes[index], newVNode.children[i], oldVNode.children[i], i)
  }
}
}//对比DOM树变更

 

posted @ 2019-03-22 15:44  cecelia  阅读(347)  评论(0编辑  收藏  举报