组件的渲染过程本质就是把这种类型的 vnode 渲染成真实 DOM
    更新组件主要做了三件事:

    • 更新组件的 vnode 节点
    • 渲染新的子树 vnode
    • 根据新旧 vnode 执行 patch 阶段

    核心 patch 逻辑:

    1. const patch = (n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, optimized = false) => {
    2. // 如果存在新旧节点, 且新旧节点类型不同,则销毁旧节点
    3. if (n1 && !isSameVNodeType(n1, n2)) {
    4. anchor = getNextHostNode(n1)
    5. unmount(n1, parentComponent, parentSuspense, true)
    6. // n1 设置为 null 保证后续都走 mount 逻辑
    7. n1 = null
    8. }
    9. const { type, shapeFlag } = n2
    10. switch (type) {
    11. case Text:
    12. // 处理文本节点
    13. break
    14. case Comment:
    15. // 处理注释节点
    16. break
    17. case Static:
    18. // 处理静态节点
    19. break
    20. case Fragment:
    21. // 处理 Fragment 元素
    22. break
    23. default:
    24. if (shapeFlag & 1 /* ELEMENT */) {
    25. // 处理普通 DOM 元素
    26. processElement(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized)
    27. }
    28. else if (shapeFlag & 6 /* COMPONENT */) {
    29. // 处理组件
    30. processComponent(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized)
    31. }
    32. else if (shapeFlag & 64 /* TELEPORT */) {
    33. // 处理 TELEPORT
    34. }
    35. else if (shapeFlag & 128 /* SUSPENSE */) {
    36. // 处理 SUSPENSE
    37. }
    38. }
    39. }
    40. function isSameVNodeType (n1, n2) {
    41. // n1 和 n2 节点的 type 和 key 都相同,才是相同节点
    42. return n1.type === n2.type && n1.key === n2.key
    43. }

    vue 的核心 patch 逻辑主要分为以下几种情况:

    • 组件
    • 普通元素
      • 纯文本
      • vnode 数组

    对于一个元素的子节点 vnode 可能会有三种情况:纯文本、vnode 数组和空。那么根据排列组合对于新旧子节点来说就有九种情况:

    • 旧子节点是纯文本:
      • 新子节点是纯文本:替换新文本
      • 新子节点是空:删除旧子节点
      • 新子节点是 vnode 数组:清空文本,添加多个子节点
    • 旧子节点是空:
      • 新子节点是纯文本:添加新文本节点
      • 新子节点是空:什么都不做
      • 新子节点是 vnode 数组:添加多个新子节点
    • 旧子节点是 vnode 数组:
      • 新子节点是纯文本:删除旧字节点,添加新文本节点
      • 新子节点是空:删除旧子节点
      • 新子节点是 vnode 数组:完整 diff 子节点(核心 diff 算法)