虚拟Dom是由普通JS对象来描述DOM对象
- 虚拟DOM可以维护程序的状态,跟踪上次的状态
- 通过比较前后两次状态差异更新真实DOM
虚拟DOM的作用和虚拟库
作用:
-
维护状态和视图的关系
-
复杂视图情况下提升渲染性能
-
跨平台
- 浏览器平台渲染DOM
- 服务端渲染SSR(Nuxt.js/Next.js)
- 原生应用(Weex/ReactNative)
- 小程序(mpvue/uniapp)
虚拟DOM中的diff算法
-
查找两棵树每一个节点的差异
-
Snabbdom对diff算法进行优化
-
DOM操作的时候很少会跨级别操作节点
-
只比较同级别的节点
-
执行过程
- oldStartVnode/newStartVnode(旧开始节点/新开始节点)
- oldEndVnode/newEndVnode(旧结束节点/新结束节点)
- oldStartVnode/newEndVnode(旧开始节点/新结束节点)
- oldEndVnode/newStartVnode(旧结束节点/新开始节点)
-
旧开始节点/新开始节点如果新旧节点是sameVnode(key和sel相同)
- 调用patchVnode()对比和更新节点
- 把旧开始和新开始往后移oldStartIdx++/oldEndIdx++
旧结束节点/新结束节点如果新旧节点不是sameVnode,会从后往前比较,比较旧结束节点和新结束节点是否是sameVnode
- 调用patchVnode()对比和更新节点
- 把旧结束和新结束往前移oldStartIdx--/oldEndIdx--
是sameVnode调用patchVnode()对比两个节点的差异(文本内容/子元素),更新真实dom
是sameVnode会重用旧节点对应的dom元素,文本内容/子元素不会进行dom操作,
旧开始节点/新结束节点是sameVnode
- 调用patchVnode()对比和更新节点
- 把oldStartVnode对应的dom元素,移动到右边,更新索引
旧结束节点/新开始节点是sameVnode
- 调用patchVnode()对比和更新节点
- 把oldEndVnode对应的dom元素,移动到左边,更新索引oldEndIdx--/newStartIdx++
都不满足,依次查找是否有相同节点
- 遍历新的开始节点查找旧节点数组中查找是否有相同key值的节点,找不到新的开始节点就是新节点,创建dom元素插入最前边
- 找到key值相同节点,判断sel是否相同,不同创建dom元素插入最前边,相同节点赋值给elemToMove,
- 调用patchVnode()对比和更新节点
- elemToMove对应的dom元素移动到最前边
循环结束
-
当老的子节点先遍历完(oldStartIdx>oldEndIdx)
- 说明新节点有剩余,把剩余节点批量插入到右边
-
当新的子节点先遍历完(newStartIdx>newEndIdx)
- 说明老节点有剩余,把剩余节点批量删除