使用JS表示一棵树
对比两棵树的差异
属性对比
子节点对比
假设现在可以英文字母唯一地标识每一个子节点: 旧的节点顺序: a b c d e f g h i 现在对节点进行了删除、插入、移动的操作。新增j节点,删除e节点,移动h节点: 新的节点顺序: a b c h d f g i j 现在知道了新旧的顺序,求最小的插入、删除操作(移动可以看成是删除和插入操作的结合)。这个问题抽象出来其实是字符串的最小编辑距离问题(Edition Distance),最常见的解决算法是 Levenshtein Distance,通过动态规划求解,时间复杂度为 O(M * N)。但是我们并不需要真的达到最小的操作,我们只需要优化一些比较常见的移动情况,牺牲一定DOM操作,让算法时间复杂度达到线性的(O(max(M, N))。具体算法细节比较多,这里不累述,有兴趣可以参考代码。
看了2种描述操作的算法:
patch1对应:https://github.com/livoras/simple-virtual-dom/blob/master/lib/diff.js
目标对象在原对象指定位置对比:
- 如果直接匹配,下一个
- 如果删除原对象即可匹配则删除,否则插入
- 删除多余的
patch2对应:https://github.com/Matt-Esch/virtual-dom/blob/master/vtree/diff.js
目标对象在原对象指定位置对比:
- 如果直接匹配,下一个
- 如果删除原对象即可匹配则删除,否则删除和插入都增加记录
示例:https://stackblitz.com/edit/react-ts-cxa9gv?file=App.tsx
5 4 2 3 1 => 3 2 1 5 4
patch1:
- insert 3 to index 0 (354231)
- insert 2 to index 1 (3254231)
- insert 1 to index 3 (32154231)
- remove index 7 (3215423)
- remove index 6 (321542)
- remove index 5 (32154)
patch2:
- remove index 0 (4231)
- remove index 0 (231)
- remove index 1 (21)
- insert 3 to index 0 (321)
- insert 5 to index 3 (3215)
- insert 4 to index 4 (32154)
1 4 2 3 5 => 5 4 2 3 1
patch1:
- insert 5 to index 0 (514235)
- remove index 1 (54235)
- insert 1 to index 4 (542315)
- remove index 5 (54231)
patch2:
- remove index 0 (4235)
- remove index 3 (423)
- insert 5 to index 0 (5423)
- inser 1 to index 4 (54231)
1 2 3 4 5 => 5 1 2 3 4
patch1:
- insert 5 to index 0 (512345)
- remove index 5 (51234)
patch2:
- remove index 4 (1234)
- insert 5 to index 0 (51234)
将差异应用于DOM
略参考
https://github.com/livoras/blog/issues/13
https://reactjs.org/docs/reconciliation.html