Skip to content

Commit dd31140

Browse files
committed
wip: render fallback nodes for empty vfor
1 parent e28b96b commit dd31140

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

packages/runtime-vapor/src/apiCreateFor.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ import { isArray, isObject, isString } from '@vue/shared'
1515
import { createComment, createTextNode } from './dom/node'
1616
import {
1717
type Block,
18+
ForFragment,
1819
VaporFragment,
1920
insert,
21+
remove,
2022
remove as removeBlock,
2123
} from './block'
2224
import { warn } from '@vue/runtime-dom'
@@ -77,7 +79,7 @@ export const createFor = (
7779
setup?: (_: {
7880
createSelector: (source: () => any) => (cb: () => void) => void
7981
}) => void,
80-
): VaporFragment => {
82+
): ForFragment => {
8183
const _insertionParent = insertionParent
8284
const _insertionAnchor = insertionAnchor
8385
if (isHydrating) {
@@ -94,7 +96,7 @@ export const createFor = (
9496
let currentKey: any
9597
// TODO handle this in hydration
9698
const parentAnchor = __DEV__ ? createComment('for') : createTextNode()
97-
const frag = new VaporFragment(oldBlocks)
99+
const frag = new ForFragment(oldBlocks)
98100
const instance = currentInstance!
99101
const canUseFastRemove = !!(flags & VaporVForFlags.FAST_REMOVE)
100102
const isComponent = !!(flags & VaporVForFlags.IS_COMPONENT)
@@ -123,6 +125,14 @@ export const createFor = (
123125
} else {
124126
parent = parent || parentAnchor!.parentNode
125127
if (!oldLength) {
128+
// remove fallback nodes if needed
129+
if (frag.fallback) {
130+
const fallbackNodes = frag.nodes[0] as any
131+
if (fallbackNodes) {
132+
remove(fallbackNodes, parent!)
133+
}
134+
}
135+
126136
// fast path for all new
127137
for (let i = 0; i < newLength; i++) {
128138
mount(source, i)
@@ -329,6 +339,11 @@ export const createFor = (
329339
frag.nodes.push(parentAnchor)
330340
}
331341

342+
// render fallback nodes if needed
343+
if (isMounted && frag.fallback && newLength === 0) {
344+
insert((frag.nodes[0] = frag.fallback()), parent!, parentAnchor)
345+
}
346+
332347
setActiveSub(prevSub)
333348
}
334349

packages/runtime-vapor/src/block.ts

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,24 @@ export type Block =
1818

1919
export type BlockFn = (...args: any[]) => Block
2020

21-
export class VaporFragment {
22-
nodes: Block
21+
export class VaporFragment<T extends Block = Block> {
22+
nodes: T
2323
anchor?: Node
2424
insert?: (parent: ParentNode, anchor: Node | null) => void
2525
remove?: (parent?: ParentNode) => void
26+
fallback?: BlockFn
2627

27-
constructor(nodes: Block) {
28+
constructor(nodes: T) {
2829
this.nodes = nodes
2930
}
3031
}
3132

33+
export class ForFragment extends VaporFragment<Block[]> {
34+
constructor(nodes: Block[]) {
35+
super(nodes)
36+
}
37+
}
38+
3239
export class DynamicFragment extends VaporFragment {
3340
anchor: Node
3441
scope: EffectScope | undefined
@@ -67,34 +74,38 @@ export class DynamicFragment extends VaporFragment {
6774

6875
if (this.fallback && !isValidBlock(this.nodes)) {
6976
parent && remove(this.nodes, parent)
70-
// handle nested dynamic fragment
71-
if (isFragment(this.nodes)) {
72-
renderFallback(this.nodes, this.fallback, key)
73-
} else {
74-
this.nodes =
75-
(this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
76-
[]
77-
}
77+
const scope = this.scope || (this.scope = new EffectScope())
78+
scope.run(() => {
79+
// handle nested fragment
80+
if (isFragment(this.nodes)) {
81+
renderFallback(this.nodes, this.fallback!)
82+
} else {
83+
this.nodes = this.fallback!() || []
84+
}
85+
})
86+
7887
parent && insert(this.nodes, parent, this.anchor)
7988
}
8089

8190
setActiveSub(prevSub)
8291
}
8392
}
8493

85-
function renderFallback(
86-
fragment: VaporFragment,
87-
fallback: BlockFn,
88-
key: any,
89-
): void {
94+
function renderFallback(fragment: VaporFragment, fallback: BlockFn): void {
95+
if (!fragment.fallback) fragment.fallback = fallback
96+
9097
if (fragment instanceof DynamicFragment) {
9198
const nodes = fragment.nodes
9299
if (isFragment(nodes)) {
93-
renderFallback(nodes, fallback, key)
100+
renderFallback(nodes, fallback)
94101
} else {
95-
if (!fragment.fallback) fragment.fallback = fallback
96-
fragment.update(fragment.fallback, key)
102+
fragment.update(fragment.fallback)
97103
}
104+
} else if (fragment instanceof ForFragment) {
105+
// TODO handle nested ForFragment
106+
fragment.nodes[0] = fallback() || []
107+
} else {
108+
// vdom slots
98109
}
99110
}
100111

0 commit comments

Comments
 (0)