用四个指针分别指向新旧子节点的头尾,然后反别对比各种情况进行DOM的位置调换。

    1. function patchKedChildren2(n1, n2, container) {
    2. const oldChildren = n1.children
    3. const newChildren = n2.children
    4. //四个索引
    5. let oldStartIndex = 0
    6. let oldEndIndex = oldChildren.length - 1
    7. let newStartIndex = 0
    8. let newEndIndex = newChildren.length - 1
    9. //四个节点
    10. let oldStartVNode = oldChildren[oldStartIndex]
    11. let oldEndVNode = oldChildren[oldEndIndex]
    12. let newStartVNode = newChildren[newStartIndex]
    13. let newEndVNode = newChildren[newEndIndex]
    14. //循环
    15. while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) {
    16. if (!oldStartVNode) {
    17. oldStartVNode = oldChildren[++oldStartIndex]
    18. } else if (!oldEndVNode) {
    19. oldEndVNode = oldChildren[--oldEndIndex]
    20. //当新旧初始节点一样时
    21. } else if (oldStartVNode.key === newStartVNode.key) {
    22. //更新一下节点
    23. patch(oldStartVNode, newStartVNode, container)
    24. //指针指向下一个
    25. oldStartVNode = oldChildren[++oldStartIndex]
    26. newStartVNode = newChildren[++newStartIndex]
    27. //新旧子节点的末尾节点key一样
    28. } else if (oldEndVNode.key === newEndVNode.key) {
    29. //更新一下节点
    30. patch(oldEndVNode, newEndVNode, container)
    31. //指针指向上一个
    32. oldEndVNode = oldChildren[--oldEndIndex]
    33. newEndVNode = newChildren[--newEndIndex]
    34. //旧字节点的开始节点和新子节点的结束节点一样
    35. } else if (oldStartVNode.key === newEndVNode.key) {
    36. patch(oldStartVNode, newEndVNode, container)
    37. //将旧开始节点的el插入到旧结束节点的后面
    38. insert(oldStartVNode.el, container, oldEndVNode.el.nextSibling)
    39. //改变指针
    40. oldStartVNode = oldChildren[++oldStartIndex]
    41. newEndVNode = newChildren[--newEndIndex]
    42. //新字节点的开始节点和旧子节点的结束节点一样
    43. } else if (newStartVNode.key === oldEndVNode.key) {
    44. patch(oldEndVNode, newStartVNode, container)
    45. //将旧字节点末尾的el插入到旧子节点开始的el 的前面
    46. insert(oldEndVNode.el, container, oldStartVNode.el)
    47. //改变指针
    48. newStartVNode = newChildren[++newStartIndex]
    49. oldEndVNode = oldChildren[--oldEndIndex]
    50. } else {
    51. //如果都找不到
    52. //直接找新字节点头 ,在旧子节点中的对应位置
    53. const index = oldChildren.findIndex((c) => {
    54. return c && newStartVNode.key === c.key
    55. })
    56. if (index > 0) {
    57. //更新
    58. patch(oldChildren[index], newStartVNode, container)
    59. //旧子节点index处el插入到旧子节点头el前
    60. insert(oldChildren[index].el, container, oldStartVNode.el)
    61. //旧字节点index处置undefined
    62. oldChildren[index] = undefined
    63. } else {
    64. //添加新元素
    65. patch(null, newStartVNode, container, oldStartVNode.el)
    66. }
    67. //新子节点头指针进一
    68. newStartVNode = newChildren[++newStartIndex]
    69. }
    70. }
    71. //添加遗漏节点
    72. if (oldEndIndex < oldStartIndex && newEndIndex >= newStartIndex) {
    73. for (let i = newStartIndex; i <= newEndIndex; i++) {
    74. patch(null, newChildren[i], container, oldStartVNode.el)
    75. }
    76. //删除节点
    77. } else if (newEndIndex < newStartIndex && oldEndIndex >= oldStartIndex) {
    78. for (let i = oldStartIndex; i <= oldEndIndex; i++) {
    79. unmount(oldChildren[i])
    80. }
    81. }
    82. }