Просмотр исходного кода

fix transition logic so previous unfinished transitions can be properly cancelled

Evan You 12 лет назад
Родитель
Сommit
11f89fbbc7
4 измененных файлов с 63 добавлено и 41 удалено
  1. 1 1
      src/directive.js
  2. 13 14
      src/directives/if.js
  3. 15 14
      src/directives/index.js
  4. 34 12
      src/transition.js

+ 1 - 1
src/directive.js

@@ -146,7 +146,7 @@ DirProto.refresh = function (value) {
         el: this.el,
         vm: this.vm
     })
-    if (value && value === this.computedValue) return
+    if (value !== undefined && value === this.computedValue) return
     this.computedValue = value
     this.apply(value)
 }

+ 13 - 14
src/directives/if.js

@@ -11,11 +11,10 @@ module.exports = {
     update: function (value) {
 
         var el       = this.el,
-            init     = this.compiler.init,
-            attached = !!el.parentNode
+            init     = this.compiler.init
 
         if (!this.parent) { // the node was detached when bound
-            if (!attached) {
+            if (!el.parentNode) {
                 return
             } else {
                 this.parent = el.parentNode
@@ -27,25 +26,25 @@ module.exports = {
             ref    = this.ref
 
         if (!value) {
-            if (attached) {
-                // insert the reference node
-                var next = el.nextSibling
-                if (next) {
-                    parent.insertBefore(ref, next)
-                } else {
-                    parent.appendChild(ref)
-                }
-                transition(el, -1, remove, init)
-            }
-        } else if (!attached) {
+            transition(el, -1, remove, init)
+        } else {
             transition(el, 1, insert, init)
         }
 
         function remove () {
+            if (!el.parentNode) return
+            // insert the reference node
+            var next = el.nextSibling
+            if (next) {
+                parent.insertBefore(ref, next)
+            } else {
+                parent.appendChild(ref)
+            }
             parent.removeChild(el)
         }
 
         function insert () {
+            if (el.parentNode) return
             parent.insertBefore(el, ref)
             parent.removeChild(ref)
         }

+ 15 - 14
src/directives/index.js

@@ -20,25 +20,17 @@ module.exports = {
         this.el.innerHTML = utils.toText(value)
     },
 
-    style: {
-        bind: function () {
-            this.arg = convertCSSProperty(this.arg)
-        },
-        update: function (value) {
-            this.el.style[this.arg] = value
-        }
+    visible: function (value) {
+        this.el.style.visibility = value ? '' : 'hidden'
     },
 
-    show: function (value, init) {
+    show: function (value) {
         var el = this.el,
+            target = value ? '' : 'none',
             change = function () {
-                el.style.display = value ? '' : 'none'
+                el.style.display = target
             }
-        transition(el, value ? 1 : -1, change, init)
-    },
-
-    visible: function (value) {
-        this.el.style.visibility = value ? '' : 'hidden'
+        transition(el, value ? 1 : -1, change, this.compiler.init)
     },
 
     'class': function (value) {
@@ -51,6 +43,15 @@ module.exports = {
             this.el.classList.add(value)
             this.lastVal = value
         }
+    },
+
+    style: {
+        bind: function () {
+            this.arg = convertCSSProperty(this.arg)
+        },
+        update: function (value) {
+            this.el.style[this.arg] = value
+        }
     }
 }
 

+ 34 - 12
src/transition.js

@@ -11,7 +11,10 @@ module.exports = function (el, stage, changeState, init) {
 
     // TODO: directly return if IE9
 
-    var className = el.sd_transition
+    var className         = el.sd_transition,
+        classList         = el.classList,
+        lastLeaveCallback = el.sd_trans_cb,
+        lastEnterTimeout  = el.sd_trans_to
 
     // in sd-repeat, the sd-transition directive
     // might not have been processed yet
@@ -30,25 +33,44 @@ module.exports = function (el, stage, changeState, init) {
         return changeState()
     }
 
-    var cl = el.classList
-
     if (stage > 0) { // enter
 
-        cl.add(className)
+        // cancel unfinished leave transition
+        if (lastLeaveCallback) {
+            el.removeEventListener(endEvent, lastLeaveCallback)
+            el.sd_trans_cb = null
+        }
+
+        // set to hidden state before appending
+        classList.add(className)
+        // append
         changeState()
-        setTimeout(function () {
-            cl.remove(className)
+        // trigger show transition next tick
+        el.sd_trans_to = setTimeout(function () {
+            classList.remove(className)
+            el.sd_trans_to = null
         }, 0)
 
     } else { // leave
 
-        cl.add(className)
+        // cancel unfinished enter transition
+        if (lastEnterTimeout) {
+            clearTimeout(lastEnterTimeout)
+            el.sd_trans_to = null
+        }
+
+        // trigger hide transition
+        classList.add(className)
+        var onEnd = function () {
+            el.removeEventListener(endEvent, onEnd)
+            el.sd_trans_cb = null
+            // actually remove node here
+            changeState()
+            classList.remove(className)
+        }
+        // attach transition end listener
         el.addEventListener(endEvent, onEnd)
+        el.sd_trans_cb = onEnd
         
     }
-
-    function onEnd () {
-        el.removeEventListener(endEvent, onEnd)
-        changeState()
-    }
 }