Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 711213f

Browse files
committed
fix(runtime-vapor): defer TransitionGroup moves until child updates flush
1 parent 4c98166 commit 711213f

3 files changed

Lines changed: 95 additions & 3 deletions

File tree

‎packages-private/vapor-e2e-test/__tests__/transition-group.spec.ts‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,43 @@ describe('vapor transition-group', () => {
641641
)
642642
})
643643

644+
test('same-key component move after prop change', async () => {
645+
const btnSelector = '.same-key-component-move-after-prop-change > button'
646+
const containerSelector = '.same-key-component-move-after-prop-change > div'
647+
648+
await expect
649+
.element(css(containerSelector))
650+
.toContainHTML(
651+
`<div class="item-wrapper">` +
652+
`<div class="item closed" id="item-1"><div class="item-inner">item 1</div></div>` +
653+
`<div class="item closed" id="item-2"><div class="item-inner">item 2</div></div>` +
654+
`<!--for--></div><!--transition-group-->`,
655+
)
656+
657+
click(btnSelector)
658+
await nextTick()
659+
await nextFrame()
660+
661+
await expect
662+
.element(css(containerSelector))
663+
.toContainHTML(
664+
`<div class="item-wrapper">` +
665+
`<div class="item opened" id="item-1"><div class="item-inner">item 1</div></div>` +
666+
`<div class="item closed group-move" id="item-2" style=""><div class="item-inner">item 2</div></div>` +
667+
`<!--for--></div><!--transition-group-->`,
668+
)
669+
670+
await transitionFinish(350)
671+
await expect
672+
.element(css(containerSelector))
673+
.toContainHTML(
674+
`<div class="item-wrapper">` +
675+
`<div class="item opened" id="item-1"><div class="item-inner">item 1</div></div>` +
676+
`<div class="item closed" id="item-2" style=""><div class="item-inner">item 2</div></div>` +
677+
`<!--for--></div><!--transition-group-->`,
678+
)
679+
})
680+
644681
test('dynamic name', async () => {
645682
const btnSelector = '.dynamic-name button.toggleBtn'
646683
const btnChangeName = '.dynamic-name button.changeNameBtn'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<script setup vapor>
2+
import { ref } from 'vue'
3+
import VaporExpandingItem from '../../components/VaporExpandingItem.vue'
4+
5+
const items = ref(
6+
[...Array(2)].map((_, i) => ({
7+
id: i + 1,
8+
isOpened: false,
9+
})),
10+
)
11+
12+
function toggleExpansion() {
13+
items.value = [
14+
{ id: 1, isOpened: true },
15+
{ id: 2, isOpened: false },
16+
]
17+
}
18+
</script>
19+
20+
<template>
21+
<div class="same-key-component-move-after-prop-change">
22+
<button @click="toggleExpansion">toggle expansion of first element</button>
23+
<div>
24+
<transition-group name="group" tag="div" class="item-wrapper">
25+
<VaporExpandingItem
26+
v-for="i in items"
27+
:key="i.id"
28+
:id="i.id"
29+
:is-opened="i.isOpened"
30+
/>
31+
</transition-group>
32+
</div>
33+
</div>
34+
</template>
35+
36+
<style>
37+
.item-wrapper {
38+
display: flex;
39+
flex-wrap: wrap;
40+
gap: 5px;
41+
width: 430px;
42+
}
43+
44+
.same-key-component-move-after-prop-change .group-move {
45+
transition: transform 300ms ease;
46+
}
47+
</style>

‎packages/runtime-vapor/src/components/TransitionGroup.ts‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,10 @@ const VaporTransitionGroupImpl = defineVaporComponent({
149149

150150
let prevChildren: ResolvedTransitionBlock[] = []
151151
// Multiple child owners can update in the same flush (e.g. a VDOM child
152-
// props update plus the surrounding v-for keyed diff). Keep the first
153-
// position snapshot until the matching updated hook applies the move.
152+
// props update plus the surrounding v-for keyed diff). Keep the first old
153+
// position snapshot, then apply moves after child render jobs have flushed.
154154
let isUpdatePending = false
155+
let isUpdatedPending = false
155156
let slottedBlock: Block = []
156157

157158
const beforeUpdate = () => {
@@ -176,7 +177,8 @@ const VaporTransitionGroupImpl = defineVaporComponent({
176177
}
177178
}
178179

179-
const updated = () => {
180+
const flushUpdated = () => {
181+
isUpdatedPending = false
180182
if (!isUpdatePending) return
181183
isUpdatePending = false
182184
if (!prevChildren.length) {
@@ -215,6 +217,12 @@ const VaporTransitionGroupImpl = defineVaporComponent({
215217
prevChildren = []
216218
}
217219

220+
const updated = () => {
221+
if (!isUpdatePending || isUpdatedPending) return
222+
isUpdatedPending = true
223+
queuePostFlushCb(flushUpdated)
224+
}
225+
218226
onBeforeUpdate(beforeUpdate)
219227
onUpdated(updated)
220228

0 commit comments

Comments
 (0)