Jinuss's blog Jinuss's blog
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

Web、WebGIS技术博客
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • reactivity响应式

  • runtime-core运行时核心模块

    • watch和watcherEffect源码解析
    • scheduler调度器
    • directive自定义指令实现原理
    • provide依赖和inject注入详解
    • 生命周期函数Lifecycle解析
    • 渲染器renderer源码解析
    • patch方法详解
    • patch中组件的挂载解析
    • patch中组件的更新解析
    • patch中DOM元素的挂载解析
    • patchDOM元素的更新解析
      • 源码解析
      • 辅助方法
        • patchBlockChildren
        • patchProp
        • patchChildren
    • patch中的双端比较快速算法
  • runtime-dom运行时DOM模块

  • 5.18源码学习》
  • runtime-core运行时核心模块
东流
2025-09-25
目录

patchDOM元素的更新解析

# 源码解析

const patchElement = (n1, n2, parentComponent, parentSuspense, namespace, slotScopeIds, optimized) => {
  const el = n2.el = n1.el;
  let { patchFlag, dynamicChildren, dirs } = n2;
  patchFlag |= n1.patchFlag & 16;
  const oldProps = n1.props || shared.EMPTY_OBJ;
  const newProps = n2.props || shared.EMPTY_OBJ;
  let vnodeHook;
  parentComponent && toggleRecurse(parentComponent, false);
  if (vnodeHook = newProps.onVnodeBeforeUpdate) {
    invokeVNodeHook(vnodeHook, parentComponent, n2, n1);
  }
  if (dirs) {
    invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate');
  }
  parentComponent && toggleRecurse(parentComponent, true);
  if (oldProps.innerHTML && newProps.innerHTML == null || oldProps.textContent && newProps.textContent == null) {
    hostSetElementText(el, "");
  }
  if (dynamicChildren) {
    patchBlockChildren(n1.dynamicChildren, dynamicChildren, el, parentComponent, parentSuspense, resolveChildrenNamespace(n2, namespace), slotScopeIds);
  } else if (!optimized) {
    patchChildren(n1, n2, el, null, parentComponent, parentSuspense, resolveChildrenNamespace(n2, namespace), slotScopeIds, false);
  }

  if (patchFlag > 0) {
    if (patchFlag & 16) {
      patchProps(el, oldProps, newProps, parentComponent, namespace)
    } else {
      if (patchFlag & 2) {
        if (oldProps.class !== newProps.class) {
          hostPatchProp(el, 'class', null, newProps.class, namespace)
        }
      }
      if (patchFlag & 4) {
        hostPatchProp(el, 'style', oldProps.style, newProps.style, namespace);
      }

      if (patchFlag & 8) {
        const propsToUpdate = n2.dynamicProps;
        for (let i = 0; i < propsToUpdate.length; i++) {
          const key = propsToUpdate[i];
          const prev = oldProps[key];
          const next = newProps[key];
          if (next !== prev || key === 'value') {
            hostPatchProp(el, key, prev, next, namespace, parentComponent)
          }
        }
      }
    }

    if (patchFlag & 1) {
      if (n1.children !== n2.children) {
        hostSetElementText(el, n2.children);
      }
    }
  } else if (!optimized && dynamicChildren == null) {
    patchProps(el, oldProps, newProps, parentComponent, namespace)
  }
  if ((vnodeHook = newProps.onVnodeUpdated) || dirs) {
    queuePostRenderEffect(() => {
      vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1);
      dirs && invokeDirectiveHook(n2, n1, parentComponent, 'updated');
    }, parentSuspense)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

# 辅助方法

# patchBlockChildren

const patchBlockChildren = (oldChildren, newChildren, fallbackContainer, parentComponent, parentSuspense, namespace, slotScopeIds) => {
  for (let i = 0; i < newChildren.length; i++) {
    const oldVNode = oldChildren[i];
    const newVNode = newChildren[i];
    const container = (oldVNode.el && (oldVNode.type === Fragment || !isSameVNodeType(oldVNode, newVNode) || oldVNode.shapeFlag & (6 | 64 | 128) ? hostParentNode(oldVNode.el) : (fallbackContainer)));

    patch(oldVNode, newVNode, container, null, parentComponent, parentSuspense, namespace, slotScopeIds, true);
  }
}
1
2
3
4
5
6
7
8
9

# patchProp

const patchProps = (el, oldProps, newProps, parentComponent, namespace) => {
  if (oldProps !== newProps) {
    if (oldProps !== shared.EMPTY_OBJ) {
       for(const key in oldProps){
         if(!shared.isReservedProp(key) && !(key in newProps)){
          hostPatchProp(el,key,oldProps[key],null,namespace,parentComponent)
         }
       }
    }

    for (const key in newProps) {
      if (shared.isReservedProp(key)) continue;
      const next = newProps[key];
      const prev = oldProps[key];
      if (next !== prev && key !== 'value') {
        hostPatchProp(el, key, prev, next, namespace, parentComponent)
      }
    }

    if ('value' in newProps) {
      hostPatchProp(el, 'value', oldProps.value, newProps.value, namespace)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# patchChildren

const patchChildren = (n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized = false) => {
  const c1 = n1 && n1.children;
  const prevShapeFlag = n1 ? n1.shapeFlag : 0;
  const c2 = n2.children;
  const { patchFlag, shapeFlag } = n2;
  if (patchFlag > 0) {
    if (patchFlag & 128) {
      patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized)
      return;
    } else if (patchFlag & 256) {
      patchUnkeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized)
      return;
    }
  }
  if (shapeFlag & 8) {
    if (prevShapeFlag & 16) {
      unmountChildren(c1, parentComponent, parentSuspense)
    }
    if (c2 != c1) {
      hostSetElementText(container, c2)
    }
  } else {
    if (prevShapeFlag & 16) {
      if (shapeFlag & 16) {
        patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized)
      } else {
        unmountChildren(c1, parentComponent, parentSuspense)
      }
    } else {
      if (prevShapeFlag & 8) {
        hostSetElementText(container, "")
      }
      if (shapeFlag & 16) {
        mountChildren(c2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized)
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
编辑 (opens new window)
上次更新: 2025/09/25, 09:41:26
patch中DOM元素的挂载解析
patch中的双端比较快速算法

← patch中DOM元素的挂载解析 patch中的双端比较快速算法→

最近更新
01
patch中的双端比较快速算法
09-25
02
patch中DOM元素的挂载解析
09-25
03
patch中组件的更新解析
09-23
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式