fix(transition): enter/leave hook timing consistency with v2
close #1145
This commit is contained in:
parent
9edbc27f45
commit
bf84ac8396
@ -3,12 +3,9 @@ import {
|
|||||||
BaseTransitionProps,
|
BaseTransitionProps,
|
||||||
h,
|
h,
|
||||||
warn,
|
warn,
|
||||||
FunctionalComponent,
|
FunctionalComponent
|
||||||
getCurrentInstance,
|
|
||||||
callWithAsyncErrorHandling
|
|
||||||
} from '@vue/runtime-core'
|
} from '@vue/runtime-core'
|
||||||
import { isObject, toNumber, extend } from '@vue/shared'
|
import { isObject, toNumber, extend } from '@vue/shared'
|
||||||
import { ErrorCodes } from 'packages/runtime-core/src/errorHandling'
|
|
||||||
|
|
||||||
const TRANSITION = 'transition'
|
const TRANSITION = 'transition'
|
||||||
const ANIMATION = 'animation'
|
const ANIMATION = 'animation'
|
||||||
@ -94,7 +91,6 @@ export function resolveTransitionProps(
|
|||||||
return baseProps
|
return baseProps
|
||||||
}
|
}
|
||||||
|
|
||||||
const instance = getCurrentInstance()!
|
|
||||||
const durations = normalizeDuration(duration)
|
const durations = normalizeDuration(duration)
|
||||||
const enterDuration = durations && durations[0]
|
const enterDuration = durations && durations[0]
|
||||||
const leaveDuration = durations && durations[1]
|
const leaveDuration = durations && durations[1]
|
||||||
@ -104,14 +100,11 @@ export function resolveTransitionProps(
|
|||||||
onEnterCancelled,
|
onEnterCancelled,
|
||||||
onLeave,
|
onLeave,
|
||||||
onLeaveCancelled,
|
onLeaveCancelled,
|
||||||
onBeforeAppear,
|
onBeforeAppear = onBeforeEnter,
|
||||||
onAppear,
|
onAppear = onEnter,
|
||||||
onAppearCancelled
|
onAppearCancelled = onEnterCancelled
|
||||||
} = baseProps
|
} = baseProps
|
||||||
|
|
||||||
type HookWithDone = (el: Element, done: () => void) => void
|
|
||||||
type Hook = HookWithDone | ((el: Element) => void)
|
|
||||||
|
|
||||||
const finishEnter = (el: Element, isAppear: boolean, done?: () => void) => {
|
const finishEnter = (el: Element, isAppear: boolean, done?: () => void) => {
|
||||||
removeTransitionClass(el, isAppear ? appearToClass : enterToClass)
|
removeTransitionClass(el, isAppear ? appearToClass : enterToClass)
|
||||||
removeTransitionClass(el, isAppear ? appearActiveClass : enterActiveClass)
|
removeTransitionClass(el, isAppear ? appearActiveClass : enterActiveClass)
|
||||||
@ -124,24 +117,12 @@ export function resolveTransitionProps(
|
|||||||
done && done()
|
done && done()
|
||||||
}
|
}
|
||||||
|
|
||||||
// only needed for user hooks called in nextFrame
|
const makeEnterHook = (isAppear: boolean) => {
|
||||||
// sync errors are already handled by BaseTransition
|
return (el: Element, done: () => void) => {
|
||||||
const callHook = (hook: Hook | undefined, args: any[]) => {
|
|
||||||
hook &&
|
|
||||||
callWithAsyncErrorHandling(
|
|
||||||
hook,
|
|
||||||
instance,
|
|
||||||
ErrorCodes.TRANSITION_HOOK,
|
|
||||||
args
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const makeEnterHook = (isAppear: boolean): HookWithDone => {
|
|
||||||
const hook = isAppear ? onAppear : onEnter
|
const hook = isAppear ? onAppear : onEnter
|
||||||
return (el, done) => {
|
|
||||||
nextFrame(() => {
|
|
||||||
const resolve = () => finishEnter(el, isAppear, done)
|
const resolve = () => finishEnter(el, isAppear, done)
|
||||||
callHook(hook, [el, resolve])
|
hook && hook(el, resolve)
|
||||||
|
nextFrame(() => {
|
||||||
removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass)
|
removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass)
|
||||||
addTransitionClass(el, isAppear ? appearToClass : enterToClass)
|
addTransitionClass(el, isAppear ? appearToClass : enterToClass)
|
||||||
if (!(hook && hook.length > 1)) {
|
if (!(hook && hook.length > 1)) {
|
||||||
@ -169,11 +150,10 @@ export function resolveTransitionProps(
|
|||||||
onEnter: makeEnterHook(false),
|
onEnter: makeEnterHook(false),
|
||||||
onAppear: makeEnterHook(true),
|
onAppear: makeEnterHook(true),
|
||||||
onLeave(el, done) {
|
onLeave(el, done) {
|
||||||
|
const resolve = () => finishLeave(el, done)
|
||||||
addTransitionClass(el, leaveActiveClass)
|
addTransitionClass(el, leaveActiveClass)
|
||||||
addTransitionClass(el, leaveFromClass)
|
addTransitionClass(el, leaveFromClass)
|
||||||
nextFrame(() => {
|
nextFrame(() => {
|
||||||
const resolve = () => finishLeave(el, done)
|
|
||||||
callHook(onLeave, [el, resolve])
|
|
||||||
removeTransitionClass(el, leaveFromClass)
|
removeTransitionClass(el, leaveFromClass)
|
||||||
addTransitionClass(el, leaveToClass)
|
addTransitionClass(el, leaveToClass)
|
||||||
if (!(onLeave && onLeave.length > 1)) {
|
if (!(onLeave && onLeave.length > 1)) {
|
||||||
@ -184,6 +164,7 @@ export function resolveTransitionProps(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
onLeave && onLeave(el, resolve)
|
||||||
},
|
},
|
||||||
onEnterCancelled(el) {
|
onEnterCancelled(el) {
|
||||||
finishEnter(el, false)
|
finishEnter(el, false)
|
||||||
|
@ -339,7 +339,7 @@ describe('e2e: Transition', () => {
|
|||||||
])
|
])
|
||||||
// todo test event with arguments. Note: not get dom, get object. '{}'
|
// todo test event with arguments. Note: not get dom, get object. '{}'
|
||||||
expect(beforeLeaveSpy).toBeCalled()
|
expect(beforeLeaveSpy).toBeCalled()
|
||||||
expect(onLeaveSpy).not.toBeCalled()
|
expect(onLeaveSpy).toBeCalled()
|
||||||
expect(afterLeaveSpy).not.toBeCalled()
|
expect(afterLeaveSpy).not.toBeCalled()
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(await classList('.test')).toStrictEqual([
|
expect(await classList('.test')).toStrictEqual([
|
||||||
@ -347,7 +347,6 @@ describe('e2e: Transition', () => {
|
|||||||
'test-leave-active',
|
'test-leave-active',
|
||||||
'test-leave-to'
|
'test-leave-to'
|
||||||
])
|
])
|
||||||
expect(beforeLeaveSpy).toBeCalled()
|
|
||||||
expect(afterLeaveSpy).not.toBeCalled()
|
expect(afterLeaveSpy).not.toBeCalled()
|
||||||
await transitionFinish()
|
await transitionFinish()
|
||||||
expect(await html('#container')).toBe('<!--v-if-->')
|
expect(await html('#container')).toBe('<!--v-if-->')
|
||||||
@ -360,7 +359,7 @@ describe('e2e: Transition', () => {
|
|||||||
'test-enter-from'
|
'test-enter-from'
|
||||||
])
|
])
|
||||||
expect(beforeEnterSpy).toBeCalled()
|
expect(beforeEnterSpy).toBeCalled()
|
||||||
expect(onEnterSpy).not.toBeCalled()
|
expect(onEnterSpy).toBeCalled()
|
||||||
expect(afterEnterSpy).not.toBeCalled()
|
expect(afterEnterSpy).not.toBeCalled()
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(await classList('.test')).toStrictEqual([
|
expect(await classList('.test')).toStrictEqual([
|
||||||
@ -368,7 +367,6 @@ describe('e2e: Transition', () => {
|
|||||||
'test-enter-active',
|
'test-enter-active',
|
||||||
'test-enter-to'
|
'test-enter-to'
|
||||||
])
|
])
|
||||||
expect(onEnterSpy).toBeCalled()
|
|
||||||
expect(afterEnterSpy).not.toBeCalled()
|
expect(afterEnterSpy).not.toBeCalled()
|
||||||
await transitionFinish()
|
await transitionFinish()
|
||||||
expect(await html('#container')).toBe('<div class="test">content</div>')
|
expect(await html('#container')).toBe('<div class="test">content</div>')
|
||||||
@ -603,7 +601,7 @@ describe('e2e: Transition', () => {
|
|||||||
'test-appear-from'
|
'test-appear-from'
|
||||||
])
|
])
|
||||||
expect(beforeAppearSpy).toBeCalled()
|
expect(beforeAppearSpy).toBeCalled()
|
||||||
expect(onAppearSpy).not.toBeCalled()
|
expect(onAppearSpy).toBeCalled()
|
||||||
expect(afterAppearSpy).not.toBeCalled()
|
expect(afterAppearSpy).not.toBeCalled()
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(await classList('.test')).toStrictEqual([
|
expect(await classList('.test')).toStrictEqual([
|
||||||
@ -611,7 +609,6 @@ describe('e2e: Transition', () => {
|
|||||||
'test-appear-active',
|
'test-appear-active',
|
||||||
'test-appear-to'
|
'test-appear-to'
|
||||||
])
|
])
|
||||||
expect(onAppearSpy).toBeCalled()
|
|
||||||
expect(afterAppearSpy).not.toBeCalled()
|
expect(afterAppearSpy).not.toBeCalled()
|
||||||
await transitionFinish()
|
await transitionFinish()
|
||||||
expect(await html('#container')).toBe('<div class="test">content</div>')
|
expect(await html('#container')).toBe('<div class="test">content</div>')
|
||||||
@ -628,7 +625,7 @@ describe('e2e: Transition', () => {
|
|||||||
'test-leave-from'
|
'test-leave-from'
|
||||||
])
|
])
|
||||||
expect(beforeLeaveSpy).toBeCalled()
|
expect(beforeLeaveSpy).toBeCalled()
|
||||||
expect(onLeaveSpy).not.toBeCalled()
|
expect(onLeaveSpy).toBeCalled()
|
||||||
expect(afterLeaveSpy).not.toBeCalled()
|
expect(afterLeaveSpy).not.toBeCalled()
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(await classList('.test')).toStrictEqual([
|
expect(await classList('.test')).toStrictEqual([
|
||||||
@ -636,7 +633,6 @@ describe('e2e: Transition', () => {
|
|||||||
'test-leave-active',
|
'test-leave-active',
|
||||||
'test-leave-to'
|
'test-leave-to'
|
||||||
])
|
])
|
||||||
expect(onLeaveSpy).toBeCalled()
|
|
||||||
expect(afterLeaveSpy).not.toBeCalled()
|
expect(afterLeaveSpy).not.toBeCalled()
|
||||||
await transitionFinish()
|
await transitionFinish()
|
||||||
expect(await html('#container')).toBe('<!--v-if-->')
|
expect(await html('#container')).toBe('<!--v-if-->')
|
||||||
@ -649,7 +645,7 @@ describe('e2e: Transition', () => {
|
|||||||
'test-enter-from'
|
'test-enter-from'
|
||||||
])
|
])
|
||||||
expect(beforeEnterSpy).toBeCalled()
|
expect(beforeEnterSpy).toBeCalled()
|
||||||
expect(onEnterSpy).not.toBeCalled()
|
expect(onEnterSpy).toBeCalled()
|
||||||
expect(afterEnterSpy).not.toBeCalled()
|
expect(afterEnterSpy).not.toBeCalled()
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(await classList('.test')).toStrictEqual([
|
expect(await classList('.test')).toStrictEqual([
|
||||||
@ -657,7 +653,6 @@ describe('e2e: Transition', () => {
|
|||||||
'test-enter-active',
|
'test-enter-active',
|
||||||
'test-enter-to'
|
'test-enter-to'
|
||||||
])
|
])
|
||||||
expect(onEnterSpy).toBeCalled()
|
|
||||||
expect(afterEnterSpy).not.toBeCalled()
|
expect(afterEnterSpy).not.toBeCalled()
|
||||||
await transitionFinish()
|
await transitionFinish()
|
||||||
expect(await html('#container')).toBe('<div class="test">content</div>')
|
expect(await html('#container')).toBe('<div class="test">content</div>')
|
||||||
@ -1233,7 +1228,7 @@ describe('e2e: Transition', () => {
|
|||||||
'test-leave-from'
|
'test-leave-from'
|
||||||
])
|
])
|
||||||
expect(beforeLeaveSpy).toBeCalled()
|
expect(beforeLeaveSpy).toBeCalled()
|
||||||
expect(onLeaveSpy).not.toBeCalled()
|
expect(onLeaveSpy).toBeCalled()
|
||||||
expect(afterLeaveSpy).not.toBeCalled()
|
expect(afterLeaveSpy).not.toBeCalled()
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(await classList('.test')).toStrictEqual([
|
expect(await classList('.test')).toStrictEqual([
|
||||||
@ -1241,7 +1236,6 @@ describe('e2e: Transition', () => {
|
|||||||
'test-leave-active',
|
'test-leave-active',
|
||||||
'test-leave-to'
|
'test-leave-to'
|
||||||
])
|
])
|
||||||
expect(beforeLeaveSpy).toBeCalled()
|
|
||||||
expect(afterLeaveSpy).not.toBeCalled()
|
expect(afterLeaveSpy).not.toBeCalled()
|
||||||
await transitionFinish()
|
await transitionFinish()
|
||||||
expect(await isVisible('.test')).toBe(false)
|
expect(await isVisible('.test')).toBe(false)
|
||||||
@ -1254,7 +1248,7 @@ describe('e2e: Transition', () => {
|
|||||||
'test-enter-from'
|
'test-enter-from'
|
||||||
])
|
])
|
||||||
expect(beforeEnterSpy).toBeCalled()
|
expect(beforeEnterSpy).toBeCalled()
|
||||||
expect(onEnterSpy).not.toBeCalled()
|
expect(onEnterSpy).toBeCalled()
|
||||||
expect(afterEnterSpy).not.toBeCalled()
|
expect(afterEnterSpy).not.toBeCalled()
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(await classList('.test')).toStrictEqual([
|
expect(await classList('.test')).toStrictEqual([
|
||||||
@ -1262,7 +1256,6 @@ describe('e2e: Transition', () => {
|
|||||||
'test-enter-active',
|
'test-enter-active',
|
||||||
'test-enter-to'
|
'test-enter-to'
|
||||||
])
|
])
|
||||||
expect(onEnterSpy).toBeCalled()
|
|
||||||
expect(afterEnterSpy).not.toBeCalled()
|
expect(afterEnterSpy).not.toBeCalled()
|
||||||
await transitionFinish()
|
await transitionFinish()
|
||||||
expect(await html('#container')).toBe(
|
expect(await html('#container')).toBe(
|
||||||
|
@ -439,7 +439,7 @@ describe('e2e: TransitionGroup', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
expect(beforeAppearSpy).toBeCalled()
|
expect(beforeAppearSpy).toBeCalled()
|
||||||
expect(onAppearSpy).not.toBeCalled()
|
expect(onAppearSpy).toBeCalled()
|
||||||
expect(afterAppearSpy).not.toBeCalled()
|
expect(afterAppearSpy).not.toBeCalled()
|
||||||
expect(appearHtml).toBe(
|
expect(appearHtml).toBe(
|
||||||
`<div class="test test-appear-active test-appear-from">a</div>` +
|
`<div class="test test-appear-active test-appear-from">a</div>` +
|
||||||
@ -447,7 +447,6 @@ describe('e2e: TransitionGroup', () => {
|
|||||||
`<div class="test test-appear-active test-appear-from">c</div>`
|
`<div class="test test-appear-active test-appear-from">c</div>`
|
||||||
)
|
)
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(onAppearSpy).toBeCalled()
|
|
||||||
expect(afterAppearSpy).not.toBeCalled()
|
expect(afterAppearSpy).not.toBeCalled()
|
||||||
expect(await html('#container')).toBe(
|
expect(await html('#container')).toBe(
|
||||||
`<div class="test test-appear-active test-appear-to">a</div>` +
|
`<div class="test test-appear-active test-appear-to">a</div>` +
|
||||||
@ -470,10 +469,10 @@ describe('e2e: TransitionGroup', () => {
|
|||||||
`<div class="test test-enter-active test-enter-from">d</div>`
|
`<div class="test test-enter-active test-enter-from">d</div>`
|
||||||
)
|
)
|
||||||
expect(beforeLeaveSpy).toBeCalled()
|
expect(beforeLeaveSpy).toBeCalled()
|
||||||
expect(onLeaveSpy).not.toBeCalled()
|
expect(onLeaveSpy).toBeCalled()
|
||||||
expect(afterLeaveSpy).not.toBeCalled()
|
expect(afterLeaveSpy).not.toBeCalled()
|
||||||
expect(beforeEnterSpy).toBeCalled()
|
expect(beforeEnterSpy).toBeCalled()
|
||||||
expect(onEnterSpy).not.toBeCalled()
|
expect(onEnterSpy).toBeCalled()
|
||||||
expect(afterEnterSpy).not.toBeCalled()
|
expect(afterEnterSpy).not.toBeCalled()
|
||||||
await nextFrame()
|
await nextFrame()
|
||||||
expect(await html('#container')).toBe(
|
expect(await html('#container')).toBe(
|
||||||
@ -482,9 +481,7 @@ describe('e2e: TransitionGroup', () => {
|
|||||||
`<div class="test">c</div>` +
|
`<div class="test">c</div>` +
|
||||||
`<div class="test test-enter-active test-enter-to">d</div>`
|
`<div class="test test-enter-active test-enter-to">d</div>`
|
||||||
)
|
)
|
||||||
expect(onLeaveSpy).toBeCalled()
|
|
||||||
expect(afterLeaveSpy).not.toBeCalled()
|
expect(afterLeaveSpy).not.toBeCalled()
|
||||||
expect(onEnterSpy).toBeCalled()
|
|
||||||
expect(afterEnterSpy).not.toBeCalled()
|
expect(afterEnterSpy).not.toBeCalled()
|
||||||
await transitionFinish()
|
await transitionFinish()
|
||||||
expect(await html('#container')).toBe(
|
expect(await html('#container')).toBe(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user