diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap index 49b1f5734..6780439ec 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap @@ -71,7 +71,7 @@ export function render(_ctx) { const n4 = t0() _renderEffect(() => _setText(n4, _ctx1[0].value+_ctx0[0].value)) return n4 - }) + }, null, null, n5) _insert(n2, n5) return n5 }) diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap index 68fe53dd8..2a2f16920 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap @@ -70,7 +70,7 @@ export function render(_ctx) { const n0 = _createFor(() => (_ctx.list), (_ctx0) => { const n2 = t0() return n2 - }, null, null, null, true) + }, null, null, null, null, true) return n0 }" `; diff --git a/packages/compiler-vapor/src/generators/for.ts b/packages/compiler-vapor/src/generators/for.ts index 21fb2ed02..ddfd61e1b 100644 --- a/packages/compiler-vapor/src/generators/for.ts +++ b/packages/compiler-vapor/src/generators/for.ts @@ -16,7 +16,18 @@ export function genFor( context: CodegenContext, ): CodeFragment[] { const { vaporHelper } = context - const { source, value, key, index, render, keyProp, once, id, memo } = oper + const { + source, + value, + key, + index, + render, + keyProp, + once, + id, + memo, + container, + } = oper let isDestructureAssignment = false let rawValue: string | null = null @@ -61,6 +72,7 @@ export function genFor( blockFn, genCallback(keyProp), genCallback(memo), + container != null && `n${container}`, false, // todo: hydrationNode once && 'true', ), diff --git a/packages/compiler-vapor/src/ir/index.ts b/packages/compiler-vapor/src/ir/index.ts index f4157a516..8e10ab0a7 100644 --- a/packages/compiler-vapor/src/ir/index.ts +++ b/packages/compiler-vapor/src/ir/index.ts @@ -86,6 +86,7 @@ export interface ForIRNode extends BaseIRNode, IRFor { keyProp?: SimpleExpressionNode render: BlockIRNode once: boolean + container?: number } export interface SetPropIRNode extends BaseIRNode { diff --git a/packages/compiler-vapor/src/transforms/vFor.ts b/packages/compiler-vapor/src/transforms/vFor.ts index a5ed245c2..735c086bf 100644 --- a/packages/compiler-vapor/src/transforms/vFor.ts +++ b/packages/compiler-vapor/src/transforms/vFor.ts @@ -56,6 +56,15 @@ export function processFor( return (): void => { exitBlock() + const { parent } = context + let container: number | undefined + if ( + parent && + parent.block.node !== parent.node && + parent.node.children.length === 1 + ) { + container = parent.reference() + } context.registerOperation({ type: IRNodeTypes.FOR, id, @@ -67,6 +76,7 @@ export function processFor( render, once: context.inVOnce, memo: memo && memo.exp, + container, }) } } diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 29913ac04..dabeb27e7 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -38,6 +38,7 @@ export const createFor = ( renderItem: (block: ForBlock['state']) => Block, getKey?: (item: any, key: any, index?: number) => any, getMemo?: (item: any, key: any, index?: number) => any[], + container?: ParentNode, hydrationNode?: Node, once?: boolean, ): Fragment => { @@ -45,7 +46,11 @@ export const createFor = ( let oldBlocks: ForBlock[] = [] let newBlocks: ForBlock[] let parent: ParentNode | undefined | null - const parentAnchor = __DEV__ ? createComment('for') : createTextNode() + const parentAnchor = container + ? undefined + : __DEV__ + ? createComment('for') + : createTextNode() const ref: Fragment = { nodes: oldBlocks, [fragmentKey]: true, @@ -71,14 +76,22 @@ export const createFor = ( isMounted = true mountList(source) } else { - parent = parent || parentAnchor.parentNode + parent = parent || container || parentAnchor!.parentNode if (!oldLength) { // fast path for all new mountList(source) } else if (!newLength) { - // fast path for clearing - for (let i = 0; i < oldLength; i++) { - unmount(oldBlocks[i]) + // fast path for all removed + if (container) { + container.textContent = '' + for (let i = 0; i < oldLength; i++) { + oldBlocks[i].scope.stop() + } + } else { + // fast path for clearing + for (let i = 0; i < oldLength; i++) { + unmount(oldBlocks[i]) + } } } else if (!getKey) { // unkeyed fast path @@ -239,13 +252,16 @@ export const createFor = ( } } - ref.nodes = [(oldBlocks = newBlocks), parentAnchor] + ref.nodes = [(oldBlocks = newBlocks)] + if (parentAnchor) { + ref.nodes.push(parentAnchor) + } } function mount( source: any, idx: number, - anchor: Node = parentAnchor, + anchor: Node | undefined = parentAnchor, ): ForBlock { const scope = effectScope()