瀏覽代碼

implement same props interface for transition-group

Evan You 9 年之前
父節點
當前提交
e8552e7ff6

+ 22 - 15
src/platforms/web/runtime/components/transition-group.js

@@ -1,4 +1,5 @@
-import { warn } from 'core/util/index'
+import { warn, extend } from 'core/util/index'
+import { transitionProps, extractTransitionData } from './transition'
 
 // Because the vdom's children update algorithm is "unstable" - i.e.
 // it doesn't guarantee the relative positioning of removed elements,
@@ -9,32 +10,38 @@ import { warn } from 'core/util/index'
 // nodes will remain where they should be.
 
 export default {
-  props: ['tag'],
+  props: extend({ tag: String }, transitionProps),
 
   beforeUpdate () {
+    // force removing pass
     this.__patch__(this._vnode, this.kept)
     this._vnode = this.kept
   },
 
   render (h) {
     const prevMap = this.prevChildrenMap
-    const children = this.$slots.default || []
     const map = this.prevChildrenMap = {}
+    const rawChildren = this.$slots.default || []
+    const children = []
     const kept = []
+    const transitionData = extractTransitionData(this)
 
-    for (let i = 0; i < children.length; i++) {
-      const c = children[i]
+    for (let i = 0; i < rawChildren.length; i++) {
+      const c = rawChildren[i]
       if (c.tag) {
-        if (c.key == null) {
-          process.env.NODE_ENV !== 'production' && warn(
-            'transition-group children must be keyed.'
-          )
-          c.key = i
-        }
-        map[c.key] = c
-        ;(c.data || (c.data = {})).transition = { name: 'fade' }
-        if (prevMap && prevMap[c.key]) {
-          kept.push(c)
+        if (c.key != null) {
+          children.push(c)
+          map[c.key] = c
+          ;(c.data || (c.data = {})).transition = transitionData
+          if (prevMap && prevMap[c.key]) {
+            kept.push(c)
+          }
+        } else if (process.env.NODE_ENV !== 'production') {
+          const opts = c.componentOptions
+          const name = opts
+            ? (opts.Ctor.options.name || opts.tag)
+            : c.tag
+          warn(`<transition-group> children must be keyed: <${name}>`)
         }
       }
     }

+ 33 - 25
src/platforms/web/runtime/components/transition.js

@@ -2,20 +2,38 @@ import { warn } from 'core/util/index'
 import { noop, camelize } from 'shared/util'
 import { getRealChild, mergeVNodeHook } from 'core/vdom/helpers'
 
+export const transitionProps = {
+  name: String,
+  appear: Boolean,
+  css: Boolean,
+  mode: String,
+  enterClass: String,
+  leaveClass: String,
+  enterActiveClass: String,
+  leaveActiveClass: String,
+  appearClass: String,
+  appearActiveClass: String
+}
+
+export function extractTransitionData (comp) {
+  const data = {}
+  const options = comp.$options
+  // props
+  for (const key in options.propsData) {
+    data[key] = comp[key]
+  }
+  // events.
+  // extract listeners and pass them directly to the transition methods
+  const listeners = options._parentListeners
+  for (const key in listeners) {
+    data[camelize(key)] = listeners[key].fn
+  }
+  return data
+}
+
 export default {
   name: 'transition',
-  props: {
-    name: String,
-    appear: Boolean,
-    css: Boolean,
-    mode: String,
-    enterClass: String,
-    leaveClass: String,
-    enterActiveClass: String,
-    leaveActiveClass: String,
-    appearClass: String,
-    appearActiveClass: String
-  },
+  props: transitionProps,
   _abstract: true,
   render (h) {
     const children = this.$slots.default && this.$slots.default.filter(c => c.tag)
@@ -41,26 +59,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 = {}
-    // 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
-    }
+    const data = (child.data || (child.data = {})).transition = extractTransitionData(this)
 
     // handle transition mode
     const mode = this.mode
     const oldRawChild = this._vnode
     const oldChild = getRealChild(oldRawChild)
     if (mode && oldChild && oldChild.data && oldChild.key !== child.key) {
+      const oldData = oldChild.data.transition
       if (mode === 'out-in') {
         // return empty node and queue update when leave finishes
-        mergeVNodeHook(oldChild.data.transition, 'afterLeave', () => {
+        mergeVNodeHook(oldData, 'afterLeave', () => {
           this.$forceUpdate()
         })
         return /\d-keep-alive$/.test(rawChild.tag)
@@ -73,7 +82,6 @@ export default {
         mergeVNodeHook(data, 'afterEnter', performLeave)
         mergeVNodeHook(data, 'enterCancelled', performLeave)
 
-        const oldData = oldChild.data.transition
         mergeVNodeHook(oldData, 'delayLeave', leave => {
           delayedLeave = leave
         })