diff算法

vue引入vdom的优势

vue在已经知道哪里更新的前提下还是引入的VDOM,这是因为除了对更新的优化之外,VDOM还有其他的优势
1、VDOM将dom结构抽象出来,上层的组件同样可以抽象化具有更高的适配能力
2、VDOM的结构一致,可以跨平台渲染 如weex
3、配合diff算法进行比对更新,在最小颗粒度和对比范围找到平衡点

diff算法

https://blog.csdn.net/chenzhizhuo/article/details/101531228

平层对比减少时间复杂度n3到n,比对过程是OldVnode和vnode进行对比,以vnode的视图为结果

patchVnode()
  • 如果两个节点是静态节点直接跳过对比(在编译时会进行标记)
  • 如果两个节点的根节点不同 则直接进行替换,创建vnode节点插入dom,移除OldVnode的节点即可
  • 两个节点相同且具有比较的价值 则进行patchVnode(OldVnode, vnode)的过程,否则执行上一步
  • vode节点不是文本节点则比较:
    1、两个节点都有子节点 且子节点不同则进行updateChild()
    2、只有vnode有子节点,则进行节点创建和插入
    3、只有oldNode有子节点,则进行子节点的移除,如果是文本节点则清空
  • vnode是文本节点则将OldVnode节点置文本节点
  • 如果vnode先结束则将OldVnode中多余的节点移除
  • 如果OldVnode先结束则将vnode中多余的节点进行创建和插入
// 判断两个节点是否值得进行比对的方法是sameVnode()
function sameVnode (a, b) {
  return (
    a.key === b.key &&  // key值
    a.tag === b.tag &&  // 标签名
    a.isComment === b.isComment &&  // 是否为注释节点
    // 是否都定义了data,data包含一些具体信息,例如onclick , style
    isDef(a.data) === isDef(b.data) &&  
    sameInputType(a, b) // 当标签是的时候,type必须相同
  )
}
updateChild()

其中难点在于updateChild的过程:

  • 首先对于新旧节点和Dom视图进行标记,开始和结束索引,注意遇到undefined跳过即可
  • 第一步进行快捷对比
    1、OldStart和vStart匹配成功则都向后移动一位
    2、OldStart和vEnd匹配成功则将Dom视图的OldStart移动到最后,最后将vEnd向前移动一位,OldStart后移一位
    3、OldEnd和vEnd匹配成功则都向前移动一位
    4、OldEnd和vStart匹配成功则将Dom视图的OldEnd移动到最前,最后将vStart后移一位,OldEnd向前移动一位
  • 快捷匹配失败则进行key值匹配
    1、vStart进行key值匹配成功则将Dom视图中对应的OldIndex节点移动到vStart的位置,将OldIndex的值置为undefined,vStart后移一位
    2、匹配失败则说明该节点是新的,创建并进行插入到Dom视图中对应的OldStart前即可
例题分析
  • 将数组的第一个元素插入到最后[1,2,3,4]=> [2,3,4,1]
    1、快捷对比元素1匹配成功,则Dom更新[1,2,3,4]=>[2,3,4,1]
    2、OldStart后移 vStart前移一位,后都快捷对比成功
  • [A,B,C,D]=>[E,C,A,D,B]
    1、E快捷对比失效则进行Key值查找,查找失败则直接创建Dom更新为[E,A,B,C,D],vStart后移一位
    2、C进行快捷查找失败,进行Key查找成功,Dom更新为[E,C,A,B,D],OldVnode中C置为undefined,vStart后移一位
    3、A头匹配成功,开始节点均后移一位
    4、B快捷查找成功,Dom更新为[E,C,A,D,B],vEnd前移一位,OldStart后移一位
    5、OldStart遇到undefined跳过自动后移一位
    6、D快捷匹配成功 后移一位,跳出循环结束

功能函数

emptyNodeAt 将一个真实的无子节点的dom节点转化为vnode形式

如:

将转换为{sel:'div#a.b.c',data:{},children:[],text:undefined,elm:

}

sameVnode 比较两个vnode节点是否相似 相似patch 不同直接进行移除和添加

createElm 通过vnode来创建真实的dom节点,并将其赋值给vnode.elm 。递归将vnode节点构建成dom树 触发全局的create钩子 推进insertedVnodeQunue ,实现批量插入触发insert回调

removeVnodes 批量删除dom节点 配合invokeSestoryHook触发destory回调和createRmCb 对remove回调进行计数

addVnodes 将vnode转化后的dom节点插入daodom树的指定位置中

createRmCb当所有remove钩子触发完毕才会将节点从父节点移除

你可能感兴趣的:(diff算法)