Browse Source

Cancel animation frame when terminating a transition early

Simone Todaro 5 years ago
parent
commit
932488d0a2
1 changed files with 25 additions and 18 deletions
  1. 25 18
      src/utils.js

+ 25 - 18
src/utils.js

@@ -306,6 +306,7 @@ function modifierValue(modifiers, key, fallback) {
 export function transitionHelper(el, modifiers, hook1, hook2, styleValues, type) {
 export function transitionHelper(el, modifiers, hook1, hook2, styleValues, type) {
     // clear the previous transition if exists to avoid caching the wrong styles
     // clear the previous transition if exists to avoid caching the wrong styles
     if (el.__x_transition) {
     if (el.__x_transition) {
+        cancelAnimationFrame(el.__x_transition.nextFrame)
         el.__x_transition.callback()
         el.__x_transition.callback()
     }
     }
 
 
@@ -381,6 +382,7 @@ export function transitionClassesOut(el, component, directives, hideCallback) {
 export function transitionClasses(el, classesDuring, classesStart, classesEnd, hook1, hook2, type) {
 export function transitionClasses(el, classesDuring, classesStart, classesEnd, hook1, hook2, type) {
     // clear the previous transition if exists to avoid caching the wrong classes
     // clear the previous transition if exists to avoid caching the wrong classes
     if (el.__x_transition) {
     if (el.__x_transition) {
+        cancelAnimationFrame(el.__x_transition.nextFrame)
         el.__x_transition.callback()
         el.__x_transition.callback()
     }
     }
 
 
@@ -414,10 +416,31 @@ export function transitionClasses(el, classesDuring, classesStart, classesEnd, h
 }
 }
 
 
 export function transition(el, stages, type) {
 export function transition(el, stages, type) {
+    el.__x_transition = {
+        // Set transition type so we can avoid clearing transition if the direction is the same
+       type: type,
+        // create a callback for the last stages of the transition so we can call it
+        // from different point and early terminate it. Once will ensure that function
+        // is only called one time.
+        callback: once(() => {
+            stages.hide()
+
+            // Adding an "isConnected" check, in case the callback
+            // removed the element from the DOM.
+            if (el.isConnected) {
+                stages.cleanup()
+            }
+
+            delete el.__x_transition
+        }),
+        // This store the next animation frame so we can cancel it
+        nextFrame: null
+    }
+
     stages.start()
     stages.start()
     stages.during()
     stages.during()
 
 
-    requestAnimationFrame(() => {
+    el.__x_transition.nextFrame =requestAnimationFrame(() => {
         // Note: Safari's transitionDuration property will list out comma separated transition durations
         // Note: Safari's transitionDuration property will list out comma separated transition durations
         // for every single transition property. Let's grab the first one and call it a day.
         // for every single transition property. Let's grab the first one and call it a day.
         let duration = Number(getComputedStyle(el).transitionDuration.replace(/,.*/, '').replace('s', '')) * 1000
         let duration = Number(getComputedStyle(el).transitionDuration.replace(/,.*/, '').replace('s', '')) * 1000
@@ -428,25 +451,9 @@ export function transition(el, stages, type) {
 
 
         stages.show()
         stages.show()
 
 
-        requestAnimationFrame(() => {
+        el.__x_transition.nextFrame =requestAnimationFrame(() => {
             stages.end()
             stages.end()
 
 
-            // Set transition type so we can avoid clearing transition if the direction is the same
-            el.__x_transition = { type: type }
-
-            // Assign current transition to el in case we need to force it.
-            el.__x_transition.callback = once(() => {
-                stages.hide()
-
-                // Adding an "isConnected" check, in case the callback
-                // removed the element from the DOM.
-                if (el.isConnected) {
-                    stages.cleanup()
-                }
-
-                delete el.__x_transition
-            })
-
             setTimeout(el.__x_transition.callback, duration)
             setTimeout(el.__x_transition.callback, duration)
         })
         })
     });
     });