From: edison Date: Wed, 30 Jul 2025 01:25:35 +0000 (+0800) Subject: fix(runtime-vapor): resolve multiple vFor rendering issues (#13714) X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=348ffafbc67b684249a576ae66b7f626abe99ae7;p=thirdparty%2Fvuejs%2Fcore.git fix(runtime-vapor): resolve multiple vFor rendering issues (#13714) --- diff --git a/packages/runtime-vapor/__tests__/for.spec.ts b/packages/runtime-vapor/__tests__/for.spec.ts index 4e4dcf0e98..572c8af85a 100644 --- a/packages/runtime-vapor/__tests__/for.spec.ts +++ b/packages/runtime-vapor/__tests__/for.spec.ts @@ -778,7 +778,7 @@ describe('createFor', () => { ) }) - test.todo('prepend', async () => { + test('prepend', async () => { const arr = ref([4, 5]) const { host, html } = render(arr) expect(host.children.length).toBe(2) @@ -940,7 +940,7 @@ describe('createFor', () => { ) }) - test.todo('remove from beginning and insert at end', async () => { + test('remove from beginning and insert at end', async () => { const arr = ref([1, 2, 3]) const { host, html } = render(arr) expect(host.children.length).toBe(3) @@ -1028,7 +1028,7 @@ describe('createFor', () => { ) }) - test.todo('move to left & replace', async () => { + test('move to left & replace', async () => { const arr = ref([1, 2, 3, 4, 5]) const { host, html } = render(arr) expect(host.children.length).toBe(5) @@ -1044,7 +1044,7 @@ describe('createFor', () => { ) }) - test.todo('move to left and leaves hold', async () => { + test('move to left and leaves hold', async () => { const arr = ref([1, 4, 5]) const { host, html } = render(arr) expect(host.children.length).toBe(3) @@ -1058,24 +1058,21 @@ describe('createFor', () => { expect(html()).toBe(`46`) }) - test.todo( - 'moved and set to undefined element ending at the end', - async () => { - const arr = ref([2, 4, 5]) - const { host, html } = render(arr) - expect(host.children.length).toBe(3) - expect(html()).toBe( - `245`, - ) + test('moved and set to undefined element ending at the end', async () => { + const arr = ref([2, 4, 5]) + const { host, html } = render(arr) + expect(host.children.length).toBe(3) + expect(html()).toBe( + `245`, + ) - arr.value = [4, 5, 3] - await nextTick() - expect(host.children.length).toBe(3) - expect(html()).toBe( - `453`, - ) - }, - ) + arr.value = [4, 5, 3] + await nextTick() + expect(host.children.length).toBe(3) + expect(html()).toBe( + `453`, + ) + }) test('reverse element', async () => { const arr = ref([1, 2, 3, 4, 5, 6, 7, 8]) @@ -1323,7 +1320,7 @@ describe('createFor', () => { }).render() } - test.todo('move a key in non-keyed nodes with a size up', async () => { + test('move a key in non-keyed nodes with a size up', async () => { const arr = ref([1, 'a', 'b', 'c']) const { host, html } = define({ setup() { diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index dbc9ebc831..864bebb8a8 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -196,12 +196,15 @@ export const createFor = ( endOffset++ continue } - if (endOffset !== 0) { - anchorFallback = normalizeAnchor(newBlocks[currentIndex + 1].nodes) - } break } + if (endOffset !== 0) { + anchorFallback = normalizeAnchor( + newBlocks[newLength - endOffset].nodes, + ) + } + while (startOffset < sharedBlockCount - endOffset) { const currentItem = getItem(source, startOffset) const currentKey = getKey(...currentItem) @@ -251,12 +254,7 @@ export const createFor = ( previousKeyIndexPairs.length = previousKeyIndexInsertIndex const previousKeyIndexMap = new Map(previousKeyIndexPairs) - const blocksToMount: [ - blockIndex: number, - blockItem: ReturnType, - blockKey: any, - anchorOffset: number, - ][] = [] + const operations: (() => void)[] = [] const relocateOrMountBlock = ( blockIndex: number, @@ -269,21 +267,30 @@ export const createFor = ( const reusedBlock = (newBlocks[blockIndex] = oldBlocks[previousIndex]) update(reusedBlock, ...blockItem) - insert( - reusedBlock, - parent!, - anchorOffset === -1 - ? anchorFallback - : normalizeAnchor(newBlocks[anchorOffset].nodes), - ) previousKeyIndexMap.delete(blockKey) + if (previousIndex !== blockIndex) { + operations.push(() => + insert( + reusedBlock, + parent!, + anchorOffset === -1 + ? anchorFallback + : normalizeAnchor(newBlocks[anchorOffset].nodes), + ), + ) + } } else { - blocksToMount.push([ - blockIndex, - blockItem, - blockKey, - anchorOffset, - ]) + operations.push(() => + mount( + source, + blockIndex, + anchorOffset === -1 + ? anchorFallback + : normalizeAnchor(newBlocks[anchorOffset].nodes), + blockItem, + blockKey, + ), + ) } } @@ -303,7 +310,7 @@ export const createFor = ( relocateOrMountBlock(i, blockItem, blockKey, -1) } - const useFastRemove = blocksToMount.length === newLength + const useFastRemove = operations.length === newLength for (const leftoverIndex of previousKeyIndexMap.values()) { unmount( @@ -322,21 +329,9 @@ export const createFor = ( } } - for (const [ - blockIndex, - blockItem, - blockKey, - anchorOffset, - ] of blocksToMount) { - mount( - source, - blockIndex, - anchorOffset === -1 - ? anchorFallback - : normalizeAnchor(newBlocks[anchorOffset].nodes), - blockItem, - blockKey, - ) + // perform mount and move operations + for (const action of operations) { + action() } } }