From c15e502056a9668073677a5220bfa8ceeaecc517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=8C=E8=8E=9E=7E=28=3D=5E=E2=96=BD=5E=3D=29?= Date: Thu, 21 Aug 2025 14:01:33 +0800 Subject: [PATCH] fix(ui): TransitionVertical Interrupt animation (#373) --- .../Animations/TransitionVertical.vue | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/components/Animations/TransitionVertical.vue b/packages/ui/src/components/Animations/TransitionVertical.vue index 478cbb108..1331a45b2 100644 --- a/packages/ui/src/components/Animations/TransitionVertical.vue +++ b/packages/ui/src/components/Animations/TransitionVertical.vue @@ -48,6 +48,9 @@ function getElementStyle(element: HTMLElement) { } } +let animation: Animation | null = null +let lastElement: HTMLElement | null = null + function prepareElement(element: HTMLElement, initialStyle: initialStyle) { const { width } = getComputedStyle(element) element.style.width = width @@ -72,7 +75,8 @@ function animateTransition( keyframes: Keyframe[] | PropertyIndexedKeyframes | null, options?: number | KeyframeAnimationOptions, ) { - const animation = element.animate(keyframes, options) + lastElement = element + animation = element.animate(keyframes, options) // Set height to 'auto' to restore it after animation element.style.height = initialStyle.height animation.onfinish = () => { @@ -106,9 +110,22 @@ function getEnterKeyframes(height: string, initialStyle: initialStyle) { ] } +function cancelAnimation(HTMLElement: HTMLElement, overflow: string, done: () => void) { + if (HTMLElement !== lastElement) return false; + if (!animation) return false; + if (animation.playState !== 'running') return false; + animation.onfinish = () => { + HTMLElement.style.overflow = overflow; + done(); + }; + animation.reverse(); + return true; +} + function enterTransition(element: Element, done: () => void) { const HTMLElement = element as HTMLElement const initialStyle = getElementStyle(HTMLElement) + if (cancelAnimation(HTMLElement, initialStyle.overflow, done)) return const height = prepareElement(HTMLElement, initialStyle) const keyframes = getEnterKeyframes(height, initialStyle) const options = { duration: props.duration, easing: props.easingEnter } @@ -118,6 +135,7 @@ function enterTransition(element: Element, done: () => void) { function leaveTransition(element: Element, done: () => void) { const HTMLElement = element as HTMLElement const initialStyle = getElementStyle(HTMLElement) + if (cancelAnimation(HTMLElement, initialStyle.overflow, done)) return const { height } = getComputedStyle(HTMLElement) HTMLElement.style.height = height HTMLElement.style.overflow = 'hidden'