diff --git a/packages/components/transition/__tests__/index.spec.tsx b/packages/components/transition/__tests__/index.spec.tsx index c189cc6..1c94c77 100644 --- a/packages/components/transition/__tests__/index.spec.tsx +++ b/packages/components/transition/__tests__/index.spec.tsx @@ -1,15 +1,21 @@ // @vitest-environment jsdom -import { Transition } from '@deot/vc-components'; -import { mount } from '@vue/test-utils'; +import { + Transition, + TransitionCollapse, + TransitionFade, + TransitionScale, + TransitionSlide, + TransitionZoom +} from '@deot/vc-components'; describe('index.ts', () => { it('basic', () => { expect(typeof Transition).toBe('object'); - }); - it('create', async () => { - const wrapper = mount(() => ()); - - expect(wrapper.classes()).toContain('vc-transition'); + expect(typeof TransitionCollapse).toBe('object'); + expect(typeof TransitionFade).toBe('object'); + expect(typeof TransitionScale).toBe('object'); + expect(typeof TransitionSlide).toBe('object'); + expect(typeof TransitionZoom).toBe('object'); }); }); diff --git a/packages/components/transition/__tests__/transition-collapse.spec.tsx b/packages/components/transition/__tests__/transition-collapse.spec.tsx new file mode 100644 index 0000000..e9013fa --- /dev/null +++ b/packages/components/transition/__tests__/transition-collapse.spec.tsx @@ -0,0 +1,65 @@ +// @vitest-environment jsdom + +import { ref, withDirectives, vShow, createApp } from 'vue'; +import { TransitionCollapse } from '@deot/vc-components'; +import { Utils } from '@deot/dev-test'; + +describe('transition.ts', () => { + const root = document.createElement('div'); + document.body.appendChild(root); + + it('create', async () => { + const isVisible = ref(false); + const isGroup = ref(false); + const mode = ref('none'); + const methods = { + onEnter: vi.fn(), + onBeforeEnter: vi.fn(), + onAfterEnter: vi.fn(), + onBeforeLeave: vi.fn(), + onLeave: vi.fn(), + onAfterLeave: vi.fn() + }; + const app = createApp( + () => ( + + { withDirectives(
, [[vShow, isVisible.value]])} + + ) + ); + + + app.mount(root); + + isVisible.value = true; + await Utils.sleep(10); + let el = root.querySelector('div')!; + expect(el.classList.contains('v-enter-from')).toBeTruthy(); + await Utils.sleep(100); + expect(el.classList.contains('v-enter-to')).toBeTruthy(); + + isGroup.value = true; + await Utils.sleep(30); + expect(root.innerHTML).toBe(`
`); + + isVisible.value = false; + await Utils.sleep(30); + expect(methods.onBeforeEnter).toHaveBeenCalledTimes(1); + expect(methods.onAfterEnter).toHaveBeenCalledTimes(1); + expect(methods.onBeforeLeave).toHaveBeenCalledTimes(1); + expect(methods.onAfterLeave).toHaveBeenCalledTimes(1); + expect(methods.onEnter).toHaveBeenCalledTimes(1); + expect(methods.onLeave).toHaveBeenCalledTimes(1); + + mode.value = 'left-part'; + await Utils.sleep(30); + }); +}); diff --git a/packages/components/transition/__tests__/transition-fade.spec.tsx b/packages/components/transition/__tests__/transition-fade.spec.tsx new file mode 100644 index 0000000..4c03f48 --- /dev/null +++ b/packages/components/transition/__tests__/transition-fade.spec.tsx @@ -0,0 +1,35 @@ +// @vitest-environment jsdom + +import { ref, withDirectives, vShow } from 'vue'; +import { TransitionFade } from '@deot/vc-components'; +import { mount } from '@vue/test-utils'; +import { Utils } from '@deot/dev-test'; + +describe('transition-fade.ts', () => { + it('create', async () => { + const isVisible = ref(false); + const isGroup = ref(false); + const mode = ref('none'); + + const wrapper = mount( + () => ( + + { withDirectives(
, [[vShow, isVisible.value]])} + + ) + ); + let vm = wrapper.getComponent({ name: 'transition' }); + expect(vm.props('enterActiveClass')).toBe('vc-transition-fade is-in'); + expect(vm.props('leaveActiveClass')).toBe('vc-transition-fade is-out'); + + isGroup.value = true; + await Utils.sleep(1); + vm = wrapper.getComponent({ name: 'transition-group' }); + expect(vm.props('moveClass')).toBe('vc-transition-fade is-move'); + }); +}); diff --git a/packages/components/transition/__tests__/transition-scale.spec.tsx b/packages/components/transition/__tests__/transition-scale.spec.tsx new file mode 100644 index 0000000..4fedf19 --- /dev/null +++ b/packages/components/transition/__tests__/transition-scale.spec.tsx @@ -0,0 +1,35 @@ +// @vitest-environment jsdom + +import { ref, withDirectives, vShow } from 'vue'; +import { TransitionScale } from '@deot/vc-components'; +import { mount } from '@vue/test-utils'; +import { Utils } from '@deot/dev-test'; + +describe('transition-scale.ts', () => { + it('create', async () => { + const isVisible = ref(false); + const isGroup = ref(false); + const mode = ref('none'); + + const wrapper = mount( + () => ( + + { withDirectives(
, [[vShow, isVisible.value]])} + + ) + ); + let vm = wrapper.getComponent({ name: 'transition' }); + expect(vm.props('enterActiveClass')).toBe('vc-transition-scale is-in'); + expect(vm.props('leaveActiveClass')).toBe('vc-transition-scale is-out'); + + isGroup.value = true; + await Utils.sleep(1); + vm = wrapper.getComponent({ name: 'transition-group' }); + expect(vm.props('moveClass')).toBe('vc-transition-scale is-move'); + }); +}); diff --git a/packages/components/transition/__tests__/transition-slide.spec.tsx b/packages/components/transition/__tests__/transition-slide.spec.tsx new file mode 100644 index 0000000..17ac71d --- /dev/null +++ b/packages/components/transition/__tests__/transition-slide.spec.tsx @@ -0,0 +1,35 @@ +// @vitest-environment jsdom + +import { ref, withDirectives, vShow } from 'vue'; +import { TransitionSlide } from '@deot/vc-components'; +import { mount } from '@vue/test-utils'; +import { Utils } from '@deot/dev-test'; + +describe('transition-slide.ts', () => { + it('create', async () => { + const isVisible = ref(false); + const isGroup = ref(false); + const mode = ref('none'); + + const wrapper = mount( + () => ( + + { withDirectives(
, [[vShow, isVisible.value]])} + + ) + ); + let vm = wrapper.getComponent({ name: 'transition' }); + expect(vm.props('enterActiveClass')).toBe('vc-transition-slide is-in'); + expect(vm.props('leaveActiveClass')).toBe('vc-transition-slide is-out'); + + isGroup.value = true; + await Utils.sleep(1); + vm = wrapper.getComponent({ name: 'transition-group' }); + expect(vm.props('moveClass')).toBe('vc-transition-slide is-move'); + }); +}); diff --git a/packages/components/transition/__tests__/transition-zoom.spec.tsx b/packages/components/transition/__tests__/transition-zoom.spec.tsx new file mode 100644 index 0000000..fc01609 --- /dev/null +++ b/packages/components/transition/__tests__/transition-zoom.spec.tsx @@ -0,0 +1,35 @@ +// @vitest-environment jsdom + +import { ref, withDirectives, vShow } from 'vue'; +import { TransitionZoom } from '@deot/vc-components'; +import { mount } from '@vue/test-utils'; +import { Utils } from '@deot/dev-test'; + +describe('transition-zoom.ts', () => { + it('create', async () => { + const isVisible = ref(false); + const isGroup = ref(false); + const mode = ref('none'); + + const wrapper = mount( + () => ( + + { withDirectives(
, [[vShow, isVisible.value]])} + + ) + ); + let vm = wrapper.getComponent({ name: 'transition' }); + expect(vm.props('enterActiveClass')).toBe('vc-transition-zoom is-in'); + expect(vm.props('leaveActiveClass')).toBe('vc-transition-zoom is-out'); + + isGroup.value = true; + await Utils.sleep(1); + vm = wrapper.getComponent({ name: 'transition-group' }); + expect(vm.props('moveClass')).toBe('vc-transition-zoom is-move'); + }); +}); diff --git a/packages/components/transition/__tests__/transition.spec.tsx b/packages/components/transition/__tests__/transition.spec.tsx new file mode 100644 index 0000000..60720cb --- /dev/null +++ b/packages/components/transition/__tests__/transition.spec.tsx @@ -0,0 +1,66 @@ +// @vitest-environment jsdom + +import { ref, withDirectives, vShow, createApp } from 'vue'; +import { Transition as VTransition } from '@deot/vc-components'; +// import { mount } from '@vue/test-utils'; +import { Utils } from '@deot/dev-test'; + +describe('transition.ts', () => { + const root = document.createElement('div'); + document.body.appendChild(root); + + it('create', async () => { + const isVisible = ref(false); + const isGroup = ref(false); + const mode = ref('none'); + const methods = { + onEnter: vi.fn(), + onBeforeEnter: vi.fn(), + onAfterEnter: vi.fn(), + onBeforeLeave: vi.fn(), + onLeave: vi.fn(), + onAfterLeave: vi.fn() + }; + const app = createApp( + () => ( + + { withDirectives(
, [[vShow, isVisible.value]])} + + ) + ); + + + app.mount(root); + + isVisible.value = true; + await Utils.sleep(10); + let el = root.querySelector('div')!; + expect(el.classList.contains('v-enter-from')).toBeTruthy(); + await Utils.sleep(30); + expect(el.classList.contains('v-enter-to')).toBeTruthy(); + + isGroup.value = true; + await Utils.sleep(30); + expect(root.innerHTML).toBe(`
`); + + isVisible.value = false; + await Utils.sleep(30); + expect(methods.onBeforeEnter).toHaveBeenCalledTimes(1); + expect(methods.onAfterEnter).toHaveBeenCalledTimes(1); + expect(methods.onBeforeLeave).toHaveBeenCalledTimes(1); + expect(methods.onAfterLeave).toHaveBeenCalledTimes(1); + expect(methods.onEnter).toHaveBeenCalledTimes(1); + expect(methods.onLeave).toHaveBeenCalledTimes(1); + + mode.value = 'left-part'; + await Utils.sleep(30); + }); +}); diff --git a/packages/components/transition/examples/index.vue b/packages/components/transition/examples/index.vue index ee5300b..f9ae0d7 100644 --- a/packages/components/transition/examples/index.vue +++ b/packages/components/transition/examples/index.vue @@ -92,6 +92,7 @@ diff --git a/packages/components/transition/transition-collapse.ts b/packages/components/transition/transition-collapse.ts index d92800e..a104e8b 100644 --- a/packages/components/transition/transition-collapse.ts +++ b/packages/components/transition/transition-collapse.ts @@ -1,4 +1,4 @@ -import { defineComponent, h, toHandlers, mergeProps } from 'vue'; +import { defineComponent, h } from 'vue'; import { props as transitionProps } from './transition-props'; import { useTransition } from './use-transition'; @@ -11,12 +11,12 @@ export const TransitionCollapse = defineComponent({ inheritAttrs: false, setup(props, { slots, attrs: _attrs }) { const attrs = _attrs as any; - const { Wrapper, resetStyles, resetAbsolute } = useTransition(); - const getTransitionStyle = (duration = 0.3) => { + const { Wrapper, resetStyles, resetAbsolute, createNext } = useTransition(); + const getTransitionStyle = (duration) => { let style = ` - ${duration}s height ease-in-out, - ${duration}s padding-top ease-in-out, - ${duration}s padding-bottom ease-in-out + ${duration}ms height ease-in-out, + ${duration}ms padding-top ease-in-out, + ${duration}ms padding-bottom ease-in-out `; return style; }; @@ -25,8 +25,11 @@ export const TransitionCollapse = defineComponent({ let duration = (props.duration as any).enter || props.duration; el.style.transition = getTransitionStyle(duration); - // @ts-ignore - if (!el.dataset) el.dataset = {}; + /* istanbul ignore next -- @preserve */ + if (!el.dataset) { + // @ts-ignore + el.dataset = {}; + } el.dataset.oldPaddingTop = el.style.paddingTop; el.dataset.oldPaddingBottom = el.style.paddingBottom; @@ -39,21 +42,27 @@ export const TransitionCollapse = defineComponent({ attrs.onBeforeEnter?.(el); }; - const handleEnter = (el: HTMLElement) => { - el.dataset.oldOverflow = el.style.overflow; - if (el.scrollHeight !== 0) { - el.style.height = el.scrollHeight + 'px'; - el.style.paddingTop = el.dataset.oldPaddingTop + 'px'; - el.style.paddingBottom = el.dataset.oldPaddingBottom + 'px'; - } else { - el.style.height = ''; - el.style.paddingTop = el.dataset.oldPaddingTop + 'px'; - el.style.paddingBottom = el.dataset.oldPaddingBottom + 'px'; + const handleEnter = async (el: HTMLElement, done?: () => any) => { + let next = createNext(done); + try { + el.dataset.oldOverflow = el.style.overflow; + /* istanbul ignore next -- @preserve */ + if (el.scrollHeight !== 0) { + el.style.height = el.scrollHeight + 'px'; + el.style.paddingTop = el.dataset.oldPaddingTop + 'px'; + el.style.paddingBottom = el.dataset.oldPaddingBottom + 'px'; + } else { + el.style.height = ''; + el.style.paddingTop = el.dataset.oldPaddingTop + 'px'; + el.style.paddingBottom = el.dataset.oldPaddingBottom + 'px'; + } + + el.style.overflow = 'hidden'; + + attrs.onEnter?.(el); + } finally { + next(); } - - el.style.overflow = 'hidden'; - - attrs.onEnter?.(el); }; const handleAfterEnter = (el: HTMLElement) => { @@ -66,8 +75,11 @@ export const TransitionCollapse = defineComponent({ }; const handleBeforeLeave = (el: HTMLElement) => { - // @ts-ignore - if (!el.dataset) el.dataset = {}; + /* istanbul ignore next -- @preserve */ + if (!el.dataset) { + // @ts-ignore + el.dataset = {}; + } el.dataset.oldPaddingTop = el.style.paddingTop; el.dataset.oldPaddingBottom = el.style.paddingBottom; el.dataset.oldOverflow = el.style.overflow; @@ -79,24 +91,30 @@ export const TransitionCollapse = defineComponent({ attrs.onBeforeLeave?.(el); }; - const handleLeave = (el: HTMLElement) => { - let leaveDuration = (props.duration as any).leave || props.duration; - if (el.scrollHeight !== 0) { + const handleLeave = (el: HTMLElement, done?: () => any) => { + let next = createNext(done); + try { + let leaveDuration = (props.duration as any).leave || props.duration; + /* istanbul ignore next -- @preserve */ + if (el.scrollHeight !== 0) { + /** + * for safari: + * 在设置高度之后添加,否则它会突然跳到零高度 + */ + el.style.transition = getTransitionStyle(leaveDuration); + el.style.height = '0px'; + el.style.paddingTop = '0px'; + el.style.paddingBottom = '0px'; + } /** - * for safari: - * 在设置高度之后添加,否则它会突然跳到零高度 + * for group */ - el.style.transition = getTransitionStyle(leaveDuration); - el.style.height = '0px'; - el.style.paddingTop = '0px'; - el.style.paddingBottom = '0px'; - } - /** - * for group - */ - resetAbsolute(el); + resetAbsolute(el); - attrs.onLeave?.(el); + attrs.onLeave?.(el); + } finally { + next(); + } }; const handleAfterLeave = (el: HTMLElement) => { @@ -109,26 +127,24 @@ export const TransitionCollapse = defineComponent({ attrs.onAfterLeave?.(el); }; - const listeners = toHandlers({ - 'before-enter': handleBeforeEnter, - 'after-enter': handleAfterEnter, - 'enter': handleEnter, - 'before-leave': handleBeforeLeave, - 'leave': handleLeave, - 'after-leave': handleAfterLeave - }); + const listeners = { + onBeforeEnter: handleBeforeEnter, + onEnter: handleEnter, + onAfterEnter: handleAfterEnter, + onBeforeLeave: handleBeforeLeave, + onLeave: handleLeave, + onAfterLeave: handleAfterLeave + }; return () => { return h( Wrapper.value, - mergeProps( - { - tag: props.tag, - moveClass: props.group ? `vc-transition-collapse is-move` : undefined - }, - attrs, - listeners - ), + { + ...attrs, + ...listeners, + tag: props.tag, + moveClass: props.group ? `${attrs.moveClass || ''} vc-transition-collapse is-move` : undefined + }, slots ); }; diff --git a/packages/components/transition/transition-fade.ts b/packages/components/transition/transition-fade.ts index 425df4c..14606f9 100644 --- a/packages/components/transition/transition-fade.ts +++ b/packages/components/transition/transition-fade.ts @@ -1,4 +1,4 @@ -import { defineComponent, h, mergeProps } from 'vue'; +import { defineComponent, h } from 'vue'; import { props as transitionProps } from './transition-props'; import { useTransition } from './use-transition'; @@ -27,14 +27,12 @@ export const TransitionFade = defineComponent({ return () => { return h( Wrapper.value, - mergeProps( - { - tag: props.tag, - }, - classes.value, - attrs, - listeners - ), + { + ...attrs, + ...listeners, + ...classes.value, + tag: props.tag + }, slots ); }; diff --git a/packages/components/transition/transition-props.ts b/packages/components/transition/transition-props.ts index eff7e99..72f23e5 100644 --- a/packages/components/transition/transition-props.ts +++ b/packages/components/transition/transition-props.ts @@ -3,11 +3,11 @@ import type { ExtractPropTypes } from 'vue'; export const props = { /** * 进入/离开持续时间 - * {enter: .3, leave: .3} + * {enter: 300, leave: 300} */ duration: { type: [Number, Object], - default: 0.3 + default: 300 }, /** * 进入/离开延迟时间 @@ -48,7 +48,7 @@ export const props = { }, prefix: { type: String, - default: '' + default: 'vc-transition' }, mode: { type: String, diff --git a/packages/components/transition/transition-scale.ts b/packages/components/transition/transition-scale.ts index 934f1b5..0590b35 100644 --- a/packages/components/transition/transition-scale.ts +++ b/packages/components/transition/transition-scale.ts @@ -1,4 +1,4 @@ -import { defineComponent, h, mergeProps } from 'vue'; +import { defineComponent, h } from 'vue'; import type { PropType } from 'vue'; import { props as transitionProps } from './transition-props'; import { useTransition } from './use-transition'; @@ -10,7 +10,7 @@ export const TransitionScale = defineComponent({ props: { ...transitionProps, mode: { - type: String as PropType<'x' | 'y' | 'part' | 'both' | 'none'>, + type: String as PropType<'x' | 'y' | 'part' | 'both' | 'none' | string>, default: 'both', validator: (v: string) => /(part|both|y|x|none)/.test(v) }, @@ -34,14 +34,12 @@ export const TransitionScale = defineComponent({ return () => { return h( Wrapper.value, - mergeProps( - { - tag: props.tag, - }, - classes.value, - attrs, - listeners - ), + { + ...attrs, + ...listeners, + ...classes.value, + tag: props.tag + }, slots ); }; diff --git a/packages/components/transition/transition-slide.ts b/packages/components/transition/transition-slide.ts index d824729..71c5390 100644 --- a/packages/components/transition/transition-slide.ts +++ b/packages/components/transition/transition-slide.ts @@ -1,4 +1,4 @@ -import { defineComponent, h, mergeProps } from 'vue'; +import { defineComponent, h } from 'vue'; import { props as transitionProps } from './transition-props'; import { useTransition } from './use-transition'; @@ -33,14 +33,12 @@ export const TransitionSlide = defineComponent({ return () => { return h( Wrapper.value, - mergeProps( - { - tag: props.tag, - }, - classes.value, - attrs, - listeners - ), + { + ...attrs, + ...listeners, + ...classes.value, + tag: props.tag + }, slots ); }; diff --git a/packages/components/transition/transition-zoom.ts b/packages/components/transition/transition-zoom.ts index 32d24d6..21820a0 100644 --- a/packages/components/transition/transition-zoom.ts +++ b/packages/components/transition/transition-zoom.ts @@ -1,4 +1,4 @@ -import { defineComponent, h, mergeProps } from 'vue'; +import { defineComponent, h } from 'vue'; import type { PropType } from 'vue'; import { props as transitionProps } from './transition-props'; import { useTransition } from './use-transition'; @@ -10,7 +10,7 @@ export const TransitionZoom = defineComponent({ props: { ...transitionProps, mode: { - type: String as PropType<'x' | 'y' | 'center' | 'none'>, + type: String as PropType<'x' | 'y' | 'center' | 'none' | string>, default: 'x', validator: (v: string) => /^(x|y|center|none)$/.test(v) }, @@ -34,14 +34,12 @@ export const TransitionZoom = defineComponent({ return () => { return h( Wrapper.value, - mergeProps( - { - tag: props.tag, - }, - classes.value, - attrs, - listeners - ), + { + ...attrs, + ...listeners, + ...classes.value, + tag: props.tag + }, slots ); }; diff --git a/packages/components/transition/transition.ts b/packages/components/transition/transition.ts index 0fff9d1..b1d15bc 100644 --- a/packages/components/transition/transition.ts +++ b/packages/components/transition/transition.ts @@ -1,4 +1,4 @@ -import { defineComponent, h, mergeProps } from 'vue'; +import { defineComponent, h } from 'vue'; import { props as transitionProps } from './transition-props'; import { useTransition } from './use-transition'; @@ -13,15 +13,13 @@ export const Transition = defineComponent({ const { Wrapper, listeners, classes } = useTransition(); return () => { return h( - Wrapper, - mergeProps( - { - tag: props.tag - }, - classes.value, - attrs, - listeners - ), + Wrapper.value, + { + ...attrs, + ...listeners, + ...classes.value, + tag: props.tag + }, slots ); }; diff --git a/packages/components/transition/use-transition.ts b/packages/components/transition/use-transition.ts index 42aafd0..682ed53 100644 --- a/packages/components/transition/use-transition.ts +++ b/packages/components/transition/use-transition.ts @@ -2,12 +2,12 @@ import { getCurrentInstance, computed, Transition, - TransitionGroup, - toHandlers + TransitionGroup } from 'vue'; import type { ComponentInternalInstance, Component } from 'vue'; import type { Props } from './transition-props'; +const trim = (str: string) => str.trim().replace(/\s+/g, " "); export const useTransition = () => { const instance = getCurrentInstance() as ComponentInternalInstance; const attrs = instance.attrs as any; @@ -20,9 +20,9 @@ export const useTransition = () => { const classes = computed(() => { let modeClass = props.mode !== 'none' ? `-${props.mode}`.split('-').join(' is-') : ''; return { - enterActiveClass: `${props.prefix} ${modeClass} is-in`, - moveClass: `${props.prefix} ${modeClass} is-move`, - leaveActiveClass: `${props.prefix} ${modeClass} is-out` + enterActiveClass: trim(`${attrs.enterActiveClass || ''} ${props.prefix} ${modeClass} is-in`), + leaveActiveClass: trim(`${attrs.leaveActiveClass || ''} ${props.prefix} ${modeClass} is-out`), + moveClass: props.group ? trim(`${attrs.moveClass || ''} ${props.prefix} ${modeClass} is-move`) : undefined, }; }); @@ -59,18 +59,30 @@ export const useTransition = () => { // hooks const handleBeforeEnter = (el: HTMLElement) => { let duration = (props.duration as any).enter || props.duration; - el.style.animationDuration = `${duration}s`; + el.style.animationDuration = `${duration}ms`; let delay = (props.delay as any).enter || props.delay; - el.style.animationDelay = `${delay}s`; + el.style.animationDelay = `${delay}ms`; resetStyles(el); attrs.onBeforeEnter?.(el); }; - const handleEnter = (el: HTMLElement) => { - attrs.onEnter?.(el); + const createNext = (callback?: () => any) => { + let hasDone = false; + return () => { + !hasDone && callback?.(); + hasDone = true; + }; + }; + const handleEnter = async (el: HTMLElement, done?: () => any) => { + let next = createNext(done); + try { + await attrs.onEnter?.(el, next); + } finally { + next(); + } }; const handleAfterEnter = (el: HTMLElement) => { @@ -81,22 +93,25 @@ export const useTransition = () => { const handleBeforeLeave = (el: HTMLElement) => { let duration = (props.duration as any).leave || props.duration; - el.style.animationDuration = `${duration}s`; + el.style.animationDuration = `${duration}ms`; let delay = (props.delay as any).leave || props.delay; - el.style.animationDelay = `${delay}s`; + el.style.animationDelay = `${delay}ms`; resetStyles(el); attrs.onBeforeLeave?.(el); }; - // 特殊处理: 如果第二个参数为done, 且接收的话, 由用户管理结束 - const handleLeave = (el: HTMLElement) => { - resetAbsolute(el); - - attrs.onLeave?.(el); - + // 如果第二个参数为done, 且接收的话, 由用户管理结束 + const handleLeave = async (el: HTMLElement, done?: () => any) => { + let next = createNext(done); + try { + resetAbsolute(el); + await attrs.onLeave?.(el, next); + } finally { + next(); + } }; const handleAfterLeave = (el: HTMLElement) => { clearStyles(el); @@ -109,13 +124,14 @@ export const useTransition = () => { resetStyles, resetAbsolute, classes, - listeners: toHandlers({ - 'before-enter': handleBeforeEnter, - 'enter': handleEnter, - 'after-enter': handleAfterEnter, - 'before-leave': handleBeforeLeave, - 'leave': handleLeave, - 'after-leave': handleAfterLeave - }) + createNext, + listeners: { + onBeforeEnter: handleBeforeEnter, + onEnter: handleEnter, + onAfterEnter: handleAfterEnter, + onBeforeLeave: handleBeforeLeave, + onLeave: handleLeave, + onAfterLeave: handleAfterLeave + } }; };