浏览代码

better handling of transition hooks

Evan You 9 年之前
父节点
当前提交
ce0425357f
共有 3 个文件被更改,包括 36 次插入39 次删除
  1. 20 14
      src/platforms/web/runtime/components/transition.js
  2. 12 24
      src/platforms/web/runtime/modules/transition.js
  3. 4 1
      src/shared/util.js

+ 20 - 14
src/platforms/web/runtime/components/transition.js

@@ -1,7 +1,7 @@
-import { noop } from 'shared/util'
-import { warn, extend } from 'core/util/index'
+import { warn } from 'core/util/index'
+import { noop, camelize } from 'shared/util'
 import { leave } from 'web/runtime/modules/transition'
-import { getRealChild } from 'core/vdom/helpers'
+import { getRealChild, mergeVNodeHook } from 'core/vdom/helpers'
 
 export default {
   name: 'transition',
@@ -42,10 +42,17 @@ export default {
     // use getRealChild() to ignore abstract components e.g. keep-alive
     const child = getRealChild(rawChild)
     child.key = child.key || `__v${child.tag + this._uid}__`
-    const data = (child.data || (child.data = {})).transition = { wrapper: this }
+    const data = (child.data || (child.data = {})).transition = {}
+    // props
     for (const key in this.$options.propsData) {
       data[key] = this[key]
     }
+    // events.
+    // extract listeners and pass them directly to the transition methods
+    const listeners = this.$options._parentListeners
+    for (const key in listeners) {
+      data[camelize(key)] = listeners[key].fn
+    }
 
     // handle transition mode
     const mode = this.mode
@@ -65,17 +72,16 @@ export default {
       } else if (mode === 'in-out') {
         let delayedLeave
         const performLeave = () => { delayedLeave() }
-        extend(child.data.transition, {
-          afterEnter: performLeave,
-          enterCancelled: performLeave
+
+        mergeVNodeHook(data, 'afterEnter', performLeave)
+        mergeVNodeHook(data, 'enterCancelled', performLeave)
+
+        const oldData = oldChild.data.transition
+        mergeVNodeHook(oldData, 'delayLeave', leave => {
+          delayedLeave = leave
         })
-        extend(oldChild.data.transition, {
-          delayLeave: leave => {
-            delayedLeave = leave
-          },
-          leaveCancelled: () => {
-            delayedLeave = noop
-          }
+        mergeVNodeHook(oldData, 'leaveCancelled', () => {
+          delayedLeave = noop
         })
       } else if (process.env.NODE_ENV !== 'production') {
         warn('invalid <transition> mode: ' + mode)

+ 12 - 24
src/platforms/web/runtime/modules/transition.js

@@ -52,7 +52,6 @@ export function enter (vnode: VNodeWithData) {
   }
 
   const {
-    wrapper,
     css,
     enterClass,
     enterActiveClass,
@@ -81,7 +80,12 @@ export function enter (vnode: VNodeWithData) {
   const enterCancelledHook = isAppear ? (appearCancelled || enterCancelled) : enterCancelled
 
   const expectsCSS = css !== false
-  const userWantsControl = enterHook && enterHook.length > 2
+  const userWantsControl =
+    enterHook &&
+    // enterHook may be a bound method which exposes
+    // the length of original fn as _length
+    (enterHook._length || enterHook.length) > 2
+
   const cb = el._enterCb = once(() => {
     if (expectsCSS) {
       removeTransitionClass(el, activeClass)
@@ -91,16 +95,8 @@ export function enter (vnode: VNodeWithData) {
         removeTransitionClass(el, startClass)
       }
       enterCancelledHook && enterCancelledHook(el, vm)
-      wrapper.$emit('enter-cancelled', el, vm)
-      if (isAppear) {
-        wrapper.$emit('appear-cancelled', el, vm)
-      }
     } else {
       afterEnterHook && afterEnterHook(el, vm)
-      wrapper.$emit('after-enter', el, vm)
-      if (isAppear) {
-        wrapper.$emit('after-appear', el, vm)
-      }
     }
     el._enterCb = null
   })
@@ -113,18 +109,10 @@ export function enter (vnode: VNodeWithData) {
       pendingNode.elm._leaveCb()
     }
     enterHook && enterHook(el, vm, cb)
-    wrapper.$emit('enter', el, vm)
-    if (isAppear) {
-      wrapper.$emit('appear', el, vm)
-    }
   })
 
   // start enter transition
   beforeEnterHook && beforeEnterHook(el, vm)
-  wrapper.$emit('before-enter', el, vm)
-  if (isAppear) {
-    wrapper.$emit('before-appear', el, vm)
-  }
   if (expectsCSS) {
     addTransitionClass(el, startClass)
     addTransitionClass(el, activeClass)
@@ -157,7 +145,6 @@ export function leave (vnode: VNodeWithData, rm: Function) {
   }
 
   const {
-    wrapper,
     css,
     leaveClass,
     leaveActiveClass,
@@ -169,7 +156,12 @@ export function leave (vnode: VNodeWithData, rm: Function) {
   } = data
 
   const expectsCSS = css !== false
-  const userWantsControl = leave && leave.length > 2
+  const userWantsControl =
+    leave &&
+    // leave hook may be a bound method which exposes
+    // the length of original fn as _length
+    (leave._length || leave.length) > 2
+
   const cb = el._leaveCb = once(() => {
     if (el.parentNode && el.parentNode._pending) {
       el.parentNode._pending[vnode.key] = null
@@ -182,11 +174,9 @@ export function leave (vnode: VNodeWithData, rm: Function) {
         removeTransitionClass(el, leaveClass)
       }
       leaveCancelled && leaveCancelled(el, vm)
-      wrapper.$emit('leave-cancelled', el, vm)
     } else {
       rm()
       afterLeave && afterLeave(el, vm)
-      wrapper.$emit('after-leave', el, vm)
     }
     el._leaveCb = null
   })
@@ -203,7 +193,6 @@ export function leave (vnode: VNodeWithData, rm: Function) {
       (el.parentNode._pending || (el.parentNode._pending = {}))[vnode.key] = vnode
     }
     beforeLeave && beforeLeave(el, vm)
-    wrapper.$emit('before-leave', el, vm)
     if (expectsCSS) {
       addTransitionClass(el, leaveClass)
       addTransitionClass(el, leaveActiveClass)
@@ -215,7 +204,6 @@ export function leave (vnode: VNodeWithData, rm: Function) {
       })
     }
     leave && leave(el, vm, cb)
-    wrapper.$emit('leave', el, vm)
     if (!expectsCSS && !userWantsControl) {
       cb()
     }

+ 4 - 1
src/shared/util.js

@@ -111,7 +111,7 @@ export const hyphenate = cached((str: string): string => {
  * Simple bind, faster than native
  */
 export function bind (fn: Function, ctx: Object): Function {
-  return function (a) {
+  function boundFn (a) {
     const l: number = arguments.length
     return l
       ? l > 1
@@ -119,6 +119,9 @@ export function bind (fn: Function, ctx: Object): Function {
         : fn.call(ctx, a)
       : fn.call(ctx)
   }
+  // record original fn length
+  boundFn._length = fn.length
+  return boundFn
 }
 
 /**