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
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
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
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
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