diff --git a/packages/components/drawer/__tests__/drawer.spec.ts b/packages/components/drawer/__tests__/drawer.spec.ts index 10d34df18..6038be96b 100644 --- a/packages/components/drawer/__tests__/drawer.spec.ts +++ b/packages/components/drawer/__tests__/drawer.spec.ts @@ -1,5 +1,5 @@ import { MountingOptions, VueWrapper, flushPromises, mount } from '@vue/test-utils' -import { h } from 'vue' +import { h, nextTick } from 'vue' import { isElementVisible, renderWork } from '@tests' @@ -40,6 +40,8 @@ describe('Drawer', () => { expect(isElementVisible(document.querySelector('.ix-drawer-wrapper'))).toBe(false) await wrapper.setProps({ visible: true }) + await nextTick() + await flushPromises() const drawerWrapper = wrapper.getComponent(DrawerWrapper) @@ -195,17 +197,17 @@ describe('Drawer', () => { test('height work', async () => { const wrapper = DrawerMount({ props: { height: 400 } }) const drawerWrapper = wrapper.getComponent(DrawerWrapper) - const contentDom = drawerWrapper.find('.ix-drawer').element as HTMLElement + const getDom = () => drawerWrapper.find('.ix-drawer').element as HTMLElement - expect(contentDom.style.height).toBe('400px') + expect(getDom().style.height).toBe('400px') await wrapper.setProps({ height: '200px' }) - expect(contentDom.style.height).toBe('200px') + expect(getDom().style.height).toBe('200px') await wrapper.setProps({ height: '20%' }) - expect(contentDom.style.height).toBe('20%') + expect(getDom().style.height).toBe('20%') }) test('mask work', async () => { @@ -237,13 +239,13 @@ describe('Drawer', () => { const wrapper = DrawerMount({ props: { offset: 256 } }) const drawerWrapper = wrapper.getComponent(DrawerWrapper) - const contentDom = drawerWrapper.find('.ix-drawer').element as HTMLElement + const getDom = () => drawerWrapper.find('.ix-drawer').element as HTMLElement - expect(contentDom.style.top).toBe('256px') + expect(getDom().style.top).toBe('256px') await wrapper.setProps({ offset: '30%' }) - expect(contentDom.style.top).toBe('30%') + expect(getDom().style.top).toBe('30%') }) test('placement work', async () => { @@ -274,17 +276,17 @@ describe('Drawer', () => { test('width work', async () => { const wrapper = DrawerMount({ props: { width: 400 } }) const drawerWrapper = wrapper.getComponent(DrawerWrapper) - const contentDom = drawerWrapper.find('.ix-drawer').element as HTMLElement + const getDom = () => drawerWrapper.find('.ix-drawer').element as HTMLElement - expect(contentDom.style.width).toBe('400px') + expect(getDom().style.width).toBe('400px') await wrapper.setProps({ width: '200px' }) - expect(contentDom.style.width).toBe('200px') + expect(getDom().style.width).toBe('200px') await wrapper.setProps({ width: '20%' }) - expect(contentDom.style.width).toBe('20%') + expect(getDom().style.width).toBe('20%') }) test('zIndex work', async () => { diff --git a/packages/components/drawer/src/Drawer.tsx b/packages/components/drawer/src/Drawer.tsx index 623e131e3..189908c99 100644 --- a/packages/components/drawer/src/Drawer.tsx +++ b/packages/components/drawer/src/Drawer.tsx @@ -11,6 +11,7 @@ import { computed, defineComponent, inject, + nextTick, onBeforeUnmount, onDeactivated, onMounted, @@ -43,7 +44,7 @@ export default defineComponent({ const mask = computed(() => props.mask ?? config.mask) - const { visible, setVisible, animatedVisible, mergedVisible } = useVisible(props) + const { loaded, visible, setVisible, animatedVisible, mergedVisible } = useVisible(props) const currentZIndex = useZIndex(toRef(props, 'zIndex'), toRef(common, 'overlayZIndex'), visible) const { open, close } = useTrigger(props, setVisible) @@ -76,7 +77,7 @@ export default defineComponent({ return null } return ( - + <ɵMask class={`${mergedPrefixCls.value}-mask`} mask={mask.value} @@ -92,6 +93,29 @@ export default defineComponent({ function useVisible(props: DrawerProps) { const [visible, setVisible] = useControlledProp(props, 'visible', false) + + // because portal is lazy loaded, actual visible at the first time should be delayed + // or else transition animation will behave unexpectedly + const loaded = ref(false) + const delayedVisible = ref(false) + watch( + visible, + v => { + if (v && !loaded.value) { + loaded.value = true + + nextTick(() => { + delayedVisible.value = true + }) + } else { + delayedVisible.value = v + } + }, + { + immediate: true, + }, + ) + const animatedVisible = ref() const mergedVisible = computed(() => { @@ -109,7 +133,7 @@ function useVisible(props: DrawerProps) { } }) - return { visible, setVisible, animatedVisible, mergedVisible } + return { loaded, visible: delayedVisible, setVisible, animatedVisible, mergedVisible } } function useScrollStrategy(props: DrawerProps, mask: ComputedRef, mergedVisible: ComputedRef) { diff --git a/packages/components/drawer/src/token.ts b/packages/components/drawer/src/token.ts index bdaad34c9..bda27498f 100644 --- a/packages/components/drawer/src/token.ts +++ b/packages/components/drawer/src/token.ts @@ -15,7 +15,7 @@ export interface DrawerContext { common: CommonConfig config: DrawerConfig mergedPrefixCls: ComputedRef - visible: ComputedRef + visible: Ref animatedVisible: Ref mergedVisible: ComputedRef currentZIndex: ComputedRef diff --git a/packages/components/drawer/style/index.less b/packages/components/drawer/style/index.less index a8340acb8..2aedca1cc 100644 --- a/packages/components/drawer/style/index.less +++ b/packages/components/drawer/style/index.less @@ -19,13 +19,14 @@ } } - &-opened&-push { - transition: transform var(--ix-transition-duration-medium) var(--ix-ease-out); - transition-delay: var(--ix-transition-duration-fast); - } - - &-opened&-pull { - transition: transform var(--ix-transition-duration-medium) var(--ix-ease-in); + &-opened { + &.@{drawer-prefix}-push { + transition: transform var(--ix-transition-duration-medium) var(--ix-ease-out); + transition-delay: var(--ix-transition-duration-fast); + } + &.@{drawer-prefix}-pull { + transition: transform var(--ix-transition-duration-medium) var(--ix-ease-in); + } } &-sentinel {