@@ -17,8 +17,9 @@ export default {
1717
1818<script lang="ts" setup>
1919import { computed , onBeforeMount , ref , watch } from ' vue'
20- import { isObj , requestAnimationFrame } from ' ../common/util'
20+ import { isObj , isPromise , requestAnimationFrame } from ' ../common/util'
2121import { transitionProps } from ' ./types'
22+ import { AbortablePromise } from ' ../common/AbortablePromise'
2223
2324const getClassNames = (name ? : string ) => {
2425 if (! name ) {
@@ -54,7 +55,13 @@ const currentDuration = ref<number>(300)
5455// 类名
5556const classes = ref <string >(' ' )
5657// 用于控制enter和leave的顺序执行
57- const enterPromise = ref <Promise <void > | null >(null )
58+ const enterPromise = ref <AbortablePromise <void > | null >(null )
59+
60+ // 动画进入的生命周期
61+ const enterLifeCyclePromises = ref <AbortablePromise <unknown > | null >(null )
62+
63+ // 动画离开的生命周期
64+ const leaveLifeCyclePromises = ref <AbortablePromise <unknown > | null >(null )
5865
5966const style = computed (() => {
6067 return ` -webkit-transition-duration:${currentDuration .value }ms;transition-duration:${currentDuration .value }ms;${
@@ -75,66 +82,107 @@ onBeforeMount(() => {
7582watch (
7683 () => props .show ,
7784 (newVal ) => {
78- observerShow (newVal )
85+ handleShow (newVal )
7986 },
80- { deep: true , immediate: true }
87+ { deep: true }
8188)
8289
8390function handleClick() {
8491 emit (' click' )
8592}
8693
87- function observerShow(value : boolean ) {
88- value ? enter () : leave ()
94+ function handleShow(value : boolean ) {
95+ if (value ) {
96+ handleAbortPromise ()
97+ enter ()
98+ } else {
99+ leave ()
100+ }
101+ }
102+ /**
103+ * 取消所有的promise
104+ */
105+ function handleAbortPromise() {
106+ isPromise (enterPromise .value ) && enterPromise .value .abort ()
107+ isPromise (enterLifeCyclePromises .value ) && enterLifeCyclePromises .value .abort ()
108+ isPromise (leaveLifeCyclePromises .value ) && leaveLifeCyclePromises .value .abort ()
109+ enterPromise .value = null
110+ enterLifeCyclePromises .value = null
111+ leaveLifeCyclePromises .value = null
89112}
90113
91114function enter() {
92- if ( enterPromise .value ) return
93- enterPromise . value = new Promise (( resolve ) => {
94- const classNames = getClassNames (props .name )
95- const duration = isObj (props .duration ) ? (props .duration as any ).enter : props .duration
96- status .value = ' enter'
97- emit (' before-enter' )
98-
99- requestAnimationFrame (() => {
115+ enterPromise .value = new AbortablePromise ( async ( resolve ) => {
116+ try {
117+ const classNames = getClassNames (props .name )
118+ const duration = isObj (props .duration ) ? (props .duration as any ).enter : props .duration
119+ status .value = ' enter'
120+ emit (' before-enter' )
121+ enterLifeCyclePromises . value = requestAnimationFrame ()
122+ await enterLifeCyclePromises . value
100123 emit (' enter' )
101124 classes .value = classNames .enter
102125 currentDuration .value = duration
103- requestAnimationFrame (() => {
104- inited .value = true
105- display .value = true
106- requestAnimationFrame (() => {
107- transitionEnded .value = false
108- classes .value = classNames [' enter-to' ]
109- resolve ()
110- })
111- })
112- })
126+ enterLifeCyclePromises .value = requestAnimationFrame ()
127+ await enterLifeCyclePromises .value
128+ inited .value = true
129+ display .value = true
130+ enterLifeCyclePromises .value = requestAnimationFrame ()
131+ await enterLifeCyclePromises .value
132+ enterLifeCyclePromises .value = null
133+ transitionEnded .value = false
134+ classes .value = classNames [' enter-to' ]
135+ resolve ()
136+ } catch (error ) {
137+ /**
138+ *
139+ */
140+ }
113141 })
114142}
115- function leave() {
116- if (! enterPromise .value ) return
117- enterPromise .value .then (() => {
143+ async function leave() {
144+ if (! enterPromise .value ) {
145+ transitionEnded .value = false
146+ return onTransitionEnd ()
147+ }
148+ try {
149+ await enterPromise .value
118150 if (! display .value ) return
119151 const classNames = getClassNames (props .name )
120152 const duration = isObj (props .duration ) ? (props .duration as any ).leave : props .duration
121153 status .value = ' leave'
122154 emit (' before-leave' )
155+ currentDuration .value = duration
156+ leaveLifeCyclePromises .value = requestAnimationFrame ()
157+ await leaveLifeCyclePromises .value
158+ emit (' leave' )
159+ classes .value = classNames .leave
160+ leaveLifeCyclePromises .value = requestAnimationFrame ()
161+ await leaveLifeCyclePromises .value
162+ transitionEnded .value = false
163+ classes .value = classNames [' leave-to' ]
164+ leaveLifeCyclePromises .value = setPromise (currentDuration .value )
165+ await leaveLifeCyclePromises .value
166+ leaveLifeCyclePromises .value = null
167+ onTransitionEnd ()
168+ enterPromise .value = null
169+ } catch (error ) {
170+ /**
171+ *
172+ */
173+ }
174+ }
123175
124- requestAnimationFrame (() => {
125- emit (' leave' )
126- classes .value = classNames .leave
127- currentDuration .value = duration
128-
129- requestAnimationFrame (() => {
130- transitionEnded .value = false
131- setTimeout (() => {
132- onTransitionEnd ()
133- enterPromise .value = null
134- }, currentDuration .value )
135- classes .value = classNames [' leave-to' ]
136- })
137- })
176+ /**
177+ * 定时器promise化
178+ * @param duration 持续时间ms
179+ */
180+ function setPromise(duration : number ) {
181+ return new AbortablePromise <void >((resolve ) => {
182+ const timer = setTimeout (() => {
183+ clearTimeout (timer )
184+ resolve ()
185+ }, duration )
138186 })
139187}
140188function onTransitionEnd() {
@@ -148,6 +196,7 @@ function onTransitionEnd() {
148196 // 进入后触发
149197 emit (' after-enter' )
150198 }
199+
151200 if (! props .show && display .value ) {
152201 display .value = false
153202 }
0 commit comments