Skip to content

Commit 1b64a40

Browse files
authored
fix(runtime): array of vnode could not be patched (#27)
1 parent 8e55a3b commit 1b64a40

File tree

7 files changed

+68
-20
lines changed

7 files changed

+68
-20
lines changed

demo/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
<script type="module" src="./src/index.ts"></script>
1010
</head>
1111
<body>
12-
<app-element count="2022" ></app-element>
12+
<app-element count="1" ></app-element>
1313
</body>
1414
</html>

demo/src/App.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,10 @@ export class App extends JwcComponent {
6767
count is {String(this.count)}
6868
</button>
6969
</div>
70-
{Array.from({ length: 2 }).map((_, i) => (
71-
<>
72-
<p class="read-the-docs">
73-
Click on the Vite and Jwc logos to learn more
74-
</p>
75-
</>
70+
{Array.from({ length: this.count }).map((_, i) => (
71+
<p class="read-the-docs">
72+
点击按钮,此处应随着按钮的点击次数而变化 {String(i + 1)}
73+
</p>
7674
))}
7775
</>
7876
);

demo/vite.config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
import { defineConfig } from "vite";
2-
export default defineConfig({});
2+
export default defineConfig({
3+
resolve: {
4+
alias: {
5+
jwcjs: "../../packages/core/index.ts",
6+
},
7+
},
8+
});

packages/runtime/dom/dom.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,16 @@ export function updateElement(oldNode: VNode, newNode: VNode) {
115115
* 4. Update the child nodes of the dom node.
116116
*
117117
*/
118-
export function updateDOM(oldNode: VNode | undefined, newNode: VNode) {
118+
export function updateDOM(
119+
oldNode: VNode | undefined,
120+
newNode: VNode | VNode[]
121+
): VNode {
122+
if (Array.isArray(newNode)) {
123+
for (const child of newNode) {
124+
newNode = updateDOM(undefined, child);
125+
}
126+
return newNode as VNode;
127+
}
119128
// if the node is marked as deleted, then remove it from the dom tree
120129
if (newNode.isDeleted) {
121130
newNode.el!.parentNode!.removeChild(newNode.el!);
@@ -124,7 +133,6 @@ export function updateDOM(oldNode: VNode | undefined, newNode: VNode) {
124133

125134
// if the node is marked as new, then create a new dom node
126135
if (newNode.isNew) {
127-
console.log("create", newNode);
128136
newNode.el = createElement(newNode);
129137
return newNode;
130138
}

packages/runtime/utils/attrs.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
import { VNode } from "../v-dom";
22

3-
export function removeAttrs(vnode: VNode, attrs: string[] = ["isNew"]) {
3+
export function removeAttrs(
4+
vnode: VNode | VNode[],
5+
attrs: string[] = ["isNew"]
6+
) {
7+
if (vnode instanceof Array) {
8+
for (const node of vnode) {
9+
removeAttrs(node, attrs);
10+
}
11+
return vnode;
12+
}
413
for (const attr of attrs) {
514
vnode[attr] ? (vnode[attr] = false) : null;
615
}

packages/runtime/v-dom/diff.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { VNode } from "./vnode";
2020
*/
2121
export function diff(oldVNode: any, newVNode: any, host?: Node) {
2222
if (!oldVNode) {
23-
markNewVNode(newVNode);
23+
newVNode = markNewVNode(newVNode);
2424
}
2525
newVNode = diffRecursive(oldVNode, newVNode);
2626
const updated = updateDOM(oldVNode, newVNode);
@@ -67,6 +67,8 @@ function markNewVNode(node: VNode) {
6767
markNewVNode(child);
6868
}
6969
}
70+
node?.isNew === false && (node.isNew = true);
71+
return node;
7072
}
7173

7274
/**
@@ -83,8 +85,23 @@ function markNewVNode(node: VNode) {
8385
* @param oldVNode
8486
* @param newVNode
8587
*/
86-
function diffRecursive(oldVNode: VNode, newVNode: VNode, host?: VNode) {
87-
if (!oldVNode) return newVNode;
88+
function diffRecursive(
89+
oldVNode: VNode | undefined,
90+
newVNode: VNode,
91+
host?: VNode
92+
) {
93+
if (!oldVNode) {
94+
newVNode = markNewVNode(newVNode);
95+
return newVNode;
96+
}
97+
// the type of the vnode may be VNode[] ( x.map(() => (<></>)) )
98+
if (oldVNode instanceof Array && newVNode instanceof Array) {
99+
const maxLength = Math.max(oldVNode.length, newVNode.length);
100+
for (let i = 0; i < maxLength; i++) {
101+
newVNode[i] = diffRecursive(oldVNode[i], newVNode[i], host);
102+
}
103+
return newVNode;
104+
}
88105
// just text node
89106
if (typeof oldVNode === "string" && typeof newVNode === "string") {
90107
if (oldVNode !== newVNode) {
@@ -93,7 +110,7 @@ function diffRecursive(oldVNode: VNode, newVNode: VNode, host?: VNode) {
93110
}
94111
}
95112

96-
if (oldVNode?.isDeleted) {
113+
if (oldVNode.isDeleted) {
97114
return oldVNode;
98115
}
99116

@@ -117,7 +134,6 @@ function diffRecursive(oldVNode: VNode, newVNode: VNode, host?: VNode) {
117134
*/
118135
newVNode.isUpdated = true;
119136
}
120-
121137
// diff the child nodes of the old vnode and the new vnode
122138
if (oldVNode.children && newVNode.children) {
123139
const oldChildren = Object.values(oldVNode.children);
@@ -133,6 +149,5 @@ function diffRecursive(oldVNode: VNode, newVNode: VNode, host?: VNode) {
133149
}
134150
}
135151
}
136-
137152
return newVNode;
138153
}

packages/runtime/v-dom/patch.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,20 @@ import { updateAttributes } from "../dom/attrs";
33

44
import { VNode } from "./vnode";
55

6-
export function patch(host: Node, vnode: VNode, old: VNode, index: number) {
6+
export function patch(
7+
host: Node,
8+
vnode: VNode | VNode[],
9+
old: VNode | VNode[],
10+
index: number
11+
) {
12+
if (Array.isArray(vnode) && Array.isArray(old)) {
13+
vnode.forEach((node, index) => {
14+
patch(host, node, old[index], index);
15+
});
16+
return;
17+
}
18+
vnode = vnode as VNode;
19+
old = old as VNode;
720
if (vnode.isUpdated) {
821
// update the attributes of the dom node
922
updateAttributes(vnode.el, vnode.attributes);
@@ -24,10 +37,9 @@ export function patch(host: Node, vnode: VNode, old: VNode, index: number) {
2437
for (let index = 0; index < vnode.children.length; index++) {
2538
// find the dom node in the host node
2639
const child = host.childNodes[index];
27-
patch(child, vnode.children[index], old.children[index], index);
40+
patch(child, vnode.children[index], old?.children[index], index);
2841
continue;
2942
}
3043
}
31-
3244
return;
3345
}

0 commit comments

Comments
 (0)