mirror of https://github.com/vuejs/core.git
fix(TransitionGroup): use offsetLeft and offsetTop instead of getBoundingClientRect to avoid transform scale affect animation (#6108)
close #6105
This commit is contained in:
parent
40c4b2a876
commit
dc4dd594fb
|
|
@ -29,8 +29,13 @@ import {
|
|||
} from '@vue/runtime-core'
|
||||
import { extend } from '@vue/shared'
|
||||
|
||||
const positionMap = new WeakMap<VNode, DOMRect>()
|
||||
const newPositionMap = new WeakMap<VNode, DOMRect>()
|
||||
interface Position {
|
||||
top: number
|
||||
left: number
|
||||
}
|
||||
|
||||
const positionMap = new WeakMap<VNode, Position>()
|
||||
const newPositionMap = new WeakMap<VNode, Position>()
|
||||
const moveCbKey = Symbol('_moveCb')
|
||||
const enterCbKey = Symbol('_enterCb')
|
||||
|
||||
|
|
@ -145,10 +150,10 @@ const TransitionGroupImpl: ComponentOptions = /*@__PURE__*/ decorate({
|
|||
instance,
|
||||
),
|
||||
)
|
||||
positionMap.set(
|
||||
child,
|
||||
(child.el as Element).getBoundingClientRect(),
|
||||
)
|
||||
positionMap.set(child, {
|
||||
left: (child.el as HTMLElement).offsetLeft,
|
||||
top: (child.el as HTMLElement).offsetTop,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,7 +194,10 @@ function callPendingCbs(c: VNode) {
|
|||
}
|
||||
|
||||
function recordPosition(c: VNode) {
|
||||
newPositionMap.set(c, (c.el as Element).getBoundingClientRect())
|
||||
newPositionMap.set(c, {
|
||||
left: (c.el as HTMLElement).offsetLeft,
|
||||
top: (c.el as HTMLElement).offsetTop,
|
||||
})
|
||||
}
|
||||
|
||||
function applyTranslation(c: VNode): VNode | undefined {
|
||||
|
|
|
|||
|
|
@ -646,6 +646,62 @@ describe('e2e: TransitionGroup', () => {
|
|||
E2E_TIMEOUT,
|
||||
)
|
||||
|
||||
// #6105
|
||||
test(
|
||||
'with scale',
|
||||
async () => {
|
||||
await page().evaluate(() => {
|
||||
const { createApp, ref, onMounted } = (window as any).Vue
|
||||
createApp({
|
||||
template: `
|
||||
<div id="container">
|
||||
<div class="scale" style="transform: scale(2) translateX(50%) translateY(50%)">
|
||||
<transition-group tag="ul">
|
||||
<li v-for="item in items" :key="item">{{item}}</li>
|
||||
</transition-group>
|
||||
<button id="toggleBtn" @click="click">button</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
setup: () => {
|
||||
const items = ref(['a', 'b', 'c'])
|
||||
const click = () => {
|
||||
items.value.reverse()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const styleNode = document.createElement('style')
|
||||
styleNode.innerHTML = `.v-move {
|
||||
transition: transform 0.5s ease;
|
||||
}`
|
||||
document.body.appendChild(styleNode)
|
||||
})
|
||||
|
||||
return { items, click }
|
||||
},
|
||||
}).mount('#app')
|
||||
})
|
||||
|
||||
const original_top = await page().$eval('ul li:nth-child(1)', node => {
|
||||
return node.getBoundingClientRect().top
|
||||
})
|
||||
const new_top = await page().evaluate(() => {
|
||||
const el = document.querySelector('ul li:nth-child(1)')
|
||||
const p = new Promise(resolve => {
|
||||
el!.addEventListener('transitionstart', () => {
|
||||
const new_top = el!.getBoundingClientRect().top
|
||||
resolve(new_top)
|
||||
})
|
||||
})
|
||||
;(document.querySelector('#toggleBtn') as any)!.click()
|
||||
return p
|
||||
})
|
||||
|
||||
expect(original_top).toBeLessThan(new_top as number)
|
||||
},
|
||||
E2E_TIMEOUT,
|
||||
)
|
||||
|
||||
test(
|
||||
'not leaking after children unmounted',
|
||||
async () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue