Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit dc4dd59

Browse files
authored
fix(TransitionGroup): use offsetLeft and offsetTop instead of getBoundingClientRect to avoid transform scale affect animation (#6108)
close #6105
1 parent 40c4b2a commit dc4dd59

File tree

2 files changed

+71
-7
lines changed

2 files changed

+71
-7
lines changed

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,13 @@ import {
2929
} from '@vue/runtime-core'
3030
import { extend } from '@vue/shared'
3131

32-
const positionMap = new WeakMap<VNode, DOMRect>()
33-
const newPositionMap = new WeakMap<VNode, DOMRect>()
32+
interface Position {
33+
top: number
34+
left: number
35+
}
36+
37+
const positionMap = new WeakMap<VNode, Position>()
38+
const newPositionMap = new WeakMap<VNode, Position>()
3439
const moveCbKey = Symbol('_moveCb')
3540
const enterCbKey = Symbol('_enterCb')
3641

@@ -145,10 +150,10 @@ const TransitionGroupImpl: ComponentOptions = /*@__PURE__*/ decorate({
145150
instance,
146151
),
147152
)
148-
positionMap.set(
149-
child,
150-
(child.el as Element).getBoundingClientRect(),
151-
)
153+
positionMap.set(child,{
154+
left: (child.elasHTMLElement).offsetLeft,
155+
top: (child.el as HTMLElement).offsetTop,
156+
})
152157
}
153158
}
154159
}
@@ -189,7 +194,10 @@ function callPendingCbs(c: VNode) {
189194
}
190195

191196
function recordPosition(c: VNode) {
192-
newPositionMap.set(c, (c.el as Element).getBoundingClientRect())
197+
newPositionMap.set(c, {
198+
left: (c.el as HTMLElement).offsetLeft,
199+
top: (c.el as HTMLElement).offsetTop,
200+
})
193201
}
194202

195203
function applyTranslation(c: VNode): VNode | undefined {

‎packages/vue/__tests__/e2e/TransitionGroup.spec.ts‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,62 @@ describe('e2e: TransitionGroup', () => {
646646
E2E_TIMEOUT,
647647
)
648648

649+
// #6105
650+
test(
651+
'with scale',
652+
async () => {
653+
await page().evaluate(() => {
654+
const { createApp, ref, onMounted } = (window as any).Vue
655+
createApp({
656+
template: `
657+
<div id="container">
658+
<div class="scale" style="transform: scale(2) translateX(50%) translateY(50%)">
659+
<transition-group tag="ul">
660+
<li v-for="item in items" :key="item">{{item}}</li>
661+
</transition-group>
662+
<button id="toggleBtn" @click="click">button</button>
663+
</div>
664+
</div>
665+
`,
666+
setup: () => {
667+
const items = ref(['a', 'b', 'c'])
668+
const click = () => {
669+
items.value.reverse()
670+
}
671+
672+
onMounted(() => {
673+
const styleNode = document.createElement('style')
674+
styleNode.innerHTML = `.v-move {
675+
transition: transform 0.5s ease;
676+
}`
677+
document.body.appendChild(styleNode)
678+
})
679+
680+
return { items, click }
681+
},
682+
}).mount('#app')
683+
})
684+
685+
const original_top = await page().$eval('ul li:nth-child(1)', node => {
686+
return node.getBoundingClientRect().top
687+
})
688+
const new_top = await page().evaluate(() => {
689+
const el = document.querySelector('ul li:nth-child(1)')
690+
const p = new Promise(resolve => {
691+
el!.addEventListener('transitionstart', () => {
692+
const new_top = el!.getBoundingClientRect().top
693+
resolve(new_top)
694+
})
695+
})
696+
;(document.querySelector('#toggleBtn') as any)!.click()
697+
return p
698+
})
699+
700+
expect(original_top).toBeLessThan(new_top as number)
701+
},
702+
E2E_TIMEOUT,
703+
)
704+
649705
test(
650706
'not leaking after children unmounted',
651707
async () => {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /