浏览代码

test css+js mixed transition mode

Evan You 11 年之前
父节点
当前提交
862744cf98
共有 3 个文件被更改,包括 140 次插入58 次删除
  1. 9 7
      src/transition/transition.js
  2. 9 5
      test/unit/specs/directives/component_spec.js
  3. 122 46
      test/unit/specs/transition/transition_spec.js

+ 9 - 7
src/transition/transition.js

@@ -59,6 +59,7 @@ p.enter = function (op, cb) {
   addClass(this.el, this.enterClass)
   op()
   this.callHookWithCb('enter')
+  queue.push(this.enterNextTick)
 }
 
 /**
@@ -76,7 +77,7 @@ p.enterNextTick = function () {
     this.setupCssCb(transitionEndEvent, enterDone)
   } else if (type === TYPE_ANIMATION) {
     this.setupCssCb(animationEndEvent, enterDone)
-  } else {
+  } else if (!this.pendingJsCb) {
     enterDone()
   }
 }
@@ -88,7 +89,7 @@ p.enterNextTick = function () {
 p.enterDone = function () {
   this.jsCancel = this.pendingJsCb = null
   removeClass(this.el, this.enterClass)
-  this.callHook('enterDone')
+  this.callHook('afterEnter')
   if (this.cb) this.cb()
 }
 
@@ -106,6 +107,11 @@ p.leave = function (op, cb) {
   this.cb = cb
   addClass(this.el, this.leaveClass)
   this.callHookWithCb('leave')
+  // only need to do leaveNextTick if there's no explicit
+  // js callback
+  if (!this.pendingJsCb) {
+    queue.push(this.leaveNextTick)
+  }
 }
 
 /**
@@ -131,7 +137,7 @@ p.leaveNextTick = function () {
 p.leaveDone = function () {
   this.op()
   removeClass(this.el, this.leaveClass)
-  this.callHook('leaveDone')
+  this.callHook('afterLeave')
   if (this.cb) this.cb()
 }
 
@@ -194,10 +200,6 @@ p.callHookWithCb = function (type) {
     }
     this.jsCancel = hook.call(this.vm, this.el, this.pendingJsCb)
   }
-  // only need to handle nextTick stuff if no js cb is provided
-  if (!this.pendingJsCb) {
-    queue.push(this[type + 'NextTick'])
-  }
 }
 
 /**

+ 9 - 5
test/unit/specs/directives/component_spec.js

@@ -295,7 +295,7 @@ if (_.inBrowser) {
             },
             leave: function (el, done) {
               spy2()
-              done()
+              _.nextTick(done)
             }
           }
         }
@@ -307,9 +307,13 @@ if (_.inBrowser) {
         expect(spy2).not.toHaveBeenCalled()
         expect(el.textContent).toBe('AAABBB')
         next()
-        expect(spy2).toHaveBeenCalled()
-        expect(el.textContent).toBe('BBB')
-        done()
+        _.nextTick(function () {
+          expect(spy2).toHaveBeenCalled()
+          _.nextTick(function () {
+            expect(el.textContent).toBe('BBB')
+            done()
+          })
+        })
       })
     })
 
@@ -331,7 +335,7 @@ if (_.inBrowser) {
           test: {
             enter: function (el, done) {
               spy2()
-              done()
+              _.nextTick(done)
             },
             leave: function (el, done) {
               spy1()

+ 122 - 46
test/unit/specs/transition/transition_spec.js

@@ -6,6 +6,41 @@ var Transition = require('../../../../src/transition/transition')
 if (_.inBrowser && !_.isIE9) {
   describe('Transition', function () {
 
+    // insert a test css
+    function insertCSS (text) {
+      var cssEl = document.createElement('style')
+      cssEl.textContent = text
+      document.head.appendChild(cssEl)
+    }
+
+    var duration = '50ms'
+    insertCSS(
+      '.test {\
+        transition: opacity ' + duration + ' ease;\
+        -webkit-transition: opacity ' + duration + ' ease;}'
+    )
+    insertCSS('.test-enter, .test-leave { opacity: 0; }')
+    insertCSS(
+      '.test-anim-enter {\
+        animation: test-enter ' + duration + ';\
+        -webkit-animation: test-enter ' + duration + ';}\
+      .test-anim-leave {\
+        animation: test-leave ' + duration + ';\
+        -webkit-animation: test-leave ' + duration + ';}\
+      @keyframes test-enter {\
+        from { opacity: 0 }\
+        to { opacity: 1 }}\
+      @-webkit-keyframes test-enter {\
+        from { opacity: 0 }\
+        to { opacity: 1 }}\
+      @keyframes test-leave {\
+        from { opacity: 1 }\
+        to { opacity: 0 }}\
+      @-webkit-keyframes test-leave {\
+        from { opacity: 1 }\
+        to { opacity: 0 }}'
+    )
+
     describe('Wrapper methods', function () {
       
       var spy, el, target, parent, vm
@@ -96,49 +131,21 @@ if (_.inBrowser && !_.isIE9) {
 
     describe('CSS transitions', function () {
 
-      var duration = '50ms'
-
-      // insert a test css
-      function insertCSS (text) {
-        var cssEl = document.createElement('style')
-        cssEl.textContent = text
-        document.head.appendChild(cssEl)
-      }
-
-      insertCSS(
-        '.test {\
-          transition: opacity ' + duration + ' ease;\
-          -webkit-transition: opacity ' + duration + ' ease;}'
-      )
-      insertCSS('.test-enter, .test-leave { opacity: 0; }')
-      insertCSS(
-        '.test-anim-enter {\
-          animation: test-enter ' + duration + ';\
-          -webkit-animation: test-enter ' + duration + ';}\
-        .test-anim-leave {\
-          animation: test-leave ' + duration + ';\
-          -webkit-animation: test-leave ' + duration + ';}\
-        @keyframes test-enter {\
-          from { opacity: 0 }\
-          to { opacity: 1 }}\
-        @-webkit-keyframes test-enter {\
-          from { opacity: 0 }\
-          to { opacity: 1 }}\
-        @keyframes test-leave {\
-          from { opacity: 1 }\
-          to { opacity: 0 }}\
-        @-webkit-keyframes test-leave {\
-          from { opacity: 1 }\
-          to { opacity: 0 }}'
-      )
-
-      var vm, el, op, cb
+      var vm, el, op, cb, hooks
       beforeEach(function (done) {
         el = document.createElement('div')
         vm = new Vue({ el: el })
         op = jasmine.createSpy('css op')
         cb = jasmine.createSpy('css cb')
         document.body.appendChild(el)
+        hooks = {
+          beforeEnter: jasmine.createSpy('beforeEnter'),
+          enter: jasmine.createSpy('enter'),
+          afterEnter: jasmine.createSpy('afterEnter'),
+          beforeLeave: jasmine.createSpy('beforeLeave'),
+          leave: jasmine.createSpy('leave'),
+          afterLeave: jasmine.createSpy('afterLeave')
+        }
         // !IMPORTANT!
         // this ensures we force a layout for every test.
         _.nextTick(done)
@@ -149,18 +156,24 @@ if (_.inBrowser && !_.isIE9) {
       })
 
       it('skip on 0s duration (execute right at next frame)', function (done) {
-        el.__v_trans = new Transition(el, 'test', null, vm)
+        el.__v_trans = new Transition(el, 'test', hooks, vm)
         el.style.transition =
         el.style.WebkitTransition = 'opacity 0s ease'
         transition.apply(el, 1, op, vm, cb)
+        expect(hooks.beforeEnter).toHaveBeenCalled()
+        expect(hooks.enter).toHaveBeenCalled()
         _.nextTick(function () {
           expect(op).toHaveBeenCalled()
           expect(cb).toHaveBeenCalled()
+          expect(hooks.afterEnter).toHaveBeenCalled()
           expect(el.classList.contains('test-enter')).toBe(false)
           transition.apply(el, -1, op, vm, cb)
+          expect(hooks.beforeLeave).toHaveBeenCalled()
+          expect(hooks.leave).toHaveBeenCalled()
           _.nextTick(function () {
             expect(op.calls.count()).toBe(2)
             expect(cb.calls.count()).toBe(2)
+            expect(hooks.afterLeave).toHaveBeenCalled()
             expect(el.classList.contains('test-leave')).toBe(false)
             done()
           })
@@ -168,16 +181,22 @@ if (_.inBrowser && !_.isIE9) {
       })
 
       it('skip when no transition available', function (done) {
-        el.__v_trans = new Transition(el, 'test-no-trans', null, vm)
+        el.__v_trans = new Transition(el, 'test-no-trans', hooks, vm)
         transition.apply(el, 1, op, vm, cb)
+        expect(hooks.beforeEnter).toHaveBeenCalled()
+        expect(hooks.enter).toHaveBeenCalled()
         _.nextTick(function () {
           expect(op).toHaveBeenCalled()
           expect(cb).toHaveBeenCalled()
+          expect(hooks.afterEnter).toHaveBeenCalled()
           expect(el.classList.contains('test-no-trans-enter')).toBe(false)
           transition.apply(el, -1, op, vm, cb)
+          expect(hooks.beforeLeave).toHaveBeenCalled()
+          expect(hooks.leave).toHaveBeenCalled()
           _.nextTick(function () {
             expect(op.calls.count()).toBe(2)
             expect(cb.calls.count()).toBe(2)
+            expect(hooks.afterLeave).toHaveBeenCalled()
             expect(el.classList.contains('test-no-trans-leave')).toBe(false)
             done()
           })
@@ -186,7 +205,7 @@ if (_.inBrowser && !_.isIE9) {
 
       it('transition enter', function (done) {
         document.body.removeChild(el)
-        el.__v_trans = new Transition(el, 'test', null, vm)
+        el.__v_trans = new Transition(el, 'test', hooks, vm)
         // inline style
         el.style.transition =
         el.style.WebkitTransition = 'opacity ' + duration + ' ease'
@@ -194,32 +213,40 @@ if (_.inBrowser && !_.isIE9) {
           document.body.appendChild(el)
           op()
         }, vm, cb)
+        expect(hooks.beforeEnter).toHaveBeenCalled()
+        expect(hooks.enter).toHaveBeenCalled()
         expect(op).toHaveBeenCalled()
         expect(cb).not.toHaveBeenCalled()
         _.nextTick(function () {
           expect(el.classList.contains('test-enter')).toBe(false)
+          expect(hooks.afterEnter).not.toHaveBeenCalled()
           _.on(el, _.transitionEndEvent, function () {
             expect(cb).toHaveBeenCalled()
+            expect(hooks.afterEnter).toHaveBeenCalled()
             done()
           })
         })
       })
 
       it('transition leave', function (done) {
-        el.__v_trans = new Transition(el, 'test', null, vm)
+        el.__v_trans = new Transition(el, 'test', hooks, vm)
         // cascaded class style
         el.classList.add('test')
         // force a layout here so the transition can be triggered
         var f = el.offsetHeight
         transition.apply(el, -1, op, vm, cb)
+        expect(hooks.beforeLeave).toHaveBeenCalled()
+        expect(hooks.leave).toHaveBeenCalled()
         _.nextTick(function () {
           expect(op).not.toHaveBeenCalled()
           expect(cb).not.toHaveBeenCalled()
+          expect(hooks.afterLeave).not.toHaveBeenCalled()
           expect(el.classList.contains('test-leave')).toBe(true)
           _.on(el, _.transitionEndEvent, function () {
             expect(op).toHaveBeenCalled()
             expect(cb).toHaveBeenCalled()
             expect(el.classList.contains('test-leave')).toBe(false)
+            expect(hooks.afterLeave).toHaveBeenCalled()
             done()
           })
         })
@@ -227,39 +254,90 @@ if (_.inBrowser && !_.isIE9) {
 
       it('animation enter', function (done) {
         document.body.removeChild(el)
-        el.__v_trans = new Transition(el, 'test-anim', null, vm)
+        el.__v_trans = new Transition(el, 'test-anim', hooks, vm)
         transition.apply(el, 1, function () {
           document.body.appendChild(el)
           op()
         }, vm, cb)
+        expect(hooks.beforeEnter).toHaveBeenCalled()
+        expect(hooks.enter).toHaveBeenCalled()
         _.nextTick(function () {
           expect(op).toHaveBeenCalled()
           expect(cb).not.toHaveBeenCalled()
           expect(el.classList.contains('test-anim-enter')).toBe(true)
+          expect(hooks.afterEnter).not.toHaveBeenCalled()
           _.on(el, _.animationEndEvent, function () {
             expect(el.classList.contains('test-anim-enter')).toBe(false)
             expect(cb).toHaveBeenCalled()
+            expect(hooks.afterEnter).toHaveBeenCalled()
             done()
           })
         })
       })
 
       it('animation leave', function (done) {
-        el.__v_trans = new Transition(el, 'test-anim', null, vm)
+        el.__v_trans = new Transition(el, 'test-anim', hooks, vm)
         transition.apply(el, -1, op, vm, cb)
+        expect(hooks.beforeLeave).toHaveBeenCalled()
+        expect(hooks.leave).toHaveBeenCalled()
         _.nextTick(function () {
           expect(op).not.toHaveBeenCalled()
           expect(cb).not.toHaveBeenCalled()
           expect(el.classList.contains('test-anim-leave')).toBe(true)
+          expect(hooks.afterLeave).not.toHaveBeenCalled()
           _.on(el, _.animationEndEvent, function () {
             expect(op).toHaveBeenCalled()
             expect(cb).toHaveBeenCalled()
             expect(el.classList.contains('test-anim-leave')).toBe(false)
+            expect(hooks.afterLeave).toHaveBeenCalled()
             done()
           })
         })
       })
 
+      it('css + js hook with callback', function (done) {
+        document.body.removeChild(el)
+        el.classList.add('test')
+
+        // enter hook that expects a second argument
+        // indicates the user wants to control when the
+        // transition ends.
+        var enterCalled = false
+        hooks.enter = function (el, enterDone) {
+          enterCalled = true
+          setTimeout(function () {
+            enterDone()
+            testDone()
+          }, 100)
+        }
+
+        el.__v_trans = new Transition(el, 'test', hooks, vm)
+        transition.apply(el, 1, function () {
+          document.body.appendChild(el)
+          op()
+        }, vm, cb)
+        expect(hooks.beforeEnter).toHaveBeenCalled()
+        expect(op).toHaveBeenCalled()
+        expect(cb).not.toHaveBeenCalled()
+        expect(enterCalled).toBe(true)
+        _.nextTick(function () {
+          expect(el.classList.contains('test-enter')).toBe(false)
+          expect(hooks.afterEnter).not.toHaveBeenCalled()
+          _.on(el, _.transitionEndEvent, function () {
+            // should wait until js callback is called!
+            expect(cb).not.toHaveBeenCalled()
+            expect(hooks.afterEnter).not.toHaveBeenCalled()
+          })
+        })
+
+        // this is called by the enter hook
+        function testDone () {
+          expect(cb).toHaveBeenCalled()
+          expect(hooks.afterEnter).toHaveBeenCalled()
+          done()
+        }
+      })
+
       it('clean up unfinished css callback', function (done) {
         el.__v_trans = new Transition(el, 'test', null, vm)
         el.classList.add('test')
@@ -308,7 +386,7 @@ if (_.inBrowser && !_.isIE9) {
 
     })
 
-    describe('JavaScript transitions', function () {
+    describe('JavaScript only transitions', function () {
 
       var el, vm, op, cb, hooks, emitter
       beforeEach(function () {
@@ -404,8 +482,6 @@ if (_.inBrowser && !_.isIE9) {
           }, 30)
         }, 15)
       })
-
     })
-
   })
 }