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

make sure keep-alive and transition-mode works together

Evan You 10 лет назад
Родитель
Сommit
8df4ac081f

+ 4 - 8
src/compiler/codegen.js

@@ -72,8 +72,6 @@ function genElement (el: ASTElement): string {
         code = `_m(${staticRenderFns.length - 1})`
       }
     }
-    // check keep-alive
-    code = checkKeepAlive(el, code)
     // platform modules
     for (let i = 0; i < platformModules.length; i++) {
       const transform = platformModules[i].transformElement
@@ -81,6 +79,10 @@ function genElement (el: ASTElement): string {
         code = transform(el, code)
       }
     }
+    // check keep-alive
+    if (el.component && el.keepAlive) {
+      code = `_h(_e("KeepAlive",{props:{child:${code}}}))`
+    }
     return code
   }
 }
@@ -270,12 +272,6 @@ function genComponent (el: ASTElement): string {
   })`
 }
 
-function checkKeepAlive (el: ASTElement, code: string): string {
-  return el.keepAlive
-    ? `_h(_e("KeepAlive"),function(){return [${code}]})`
-    : code
-}
-
 function genProps (props: Array<{ name: string, value: string }>): string {
   let res = ''
   for (let i = 0; i < props.length; i++) {

+ 22 - 7
src/core/components/keep-alive.js

@@ -1,20 +1,24 @@
 export default {
   name: 'keep-alive',
   _abstract: true,
+  props: {
+    child: Object
+  },
   created () {
     this.cache = Object.create(null)
   },
   render () {
-    const childNode = this.$slots.default[0]
-    const cid = childNode.componentOptions.Ctor.cid
+    const rawChild = this.child
+    const realChild = getRealChild(this.child)
+    const cid = realChild.componentOptions.Ctor.cid
     if (this.cache[cid]) {
-      const child = childNode.child = this.cache[cid].child
-      childNode.elm = this.$el = child.$el
+      const child = realChild.child = this.cache[cid].child
+      realChild.elm = this.$el = child.$el
     } else {
-      this.cache[cid] = childNode
+      this.cache[cid] = realChild
     }
-    childNode.data.keepAlive = true
-    return childNode
+    realChild.data.keepAlive = true
+    return rawChild
   },
   beforeDestroy () {
     for (const key in this.cache) {
@@ -22,3 +26,14 @@ export default {
     }
   }
 }
+
+// in case the child is also an abstract component, e.g. <transition-control>
+// we want to recrusively retrieve the real component to be rendered
+function getRealChild (vnode) {
+  const compOptions = vnode && vnode.componentOptions
+  if (compOptions && compOptions.Ctor.options._abstract) {
+    return getRealChild(compOptions.propsData.child)
+  } else {
+    return vnode
+  }
+}

+ 1 - 1
src/platforms/web/compiler/modules/transition.js

@@ -28,7 +28,7 @@ function transformElement (el: ASTElement, code: string): string {
   return el.transitionMode
     ? `_h(_e('TransitionControl',{props:{mode:${
         el.transitionMode
-      }}}),function(){return [${code}]})`
+      },child:${code}}}))`
     : code
 }
 

+ 12 - 16
src/platforms/web/runtime/components/transition-control.js

@@ -6,6 +6,7 @@ export default {
   name: 'transition-control',
   _abstract: true,
   props: {
+    child: Object,
     mode: {
       validator (val) {
         if (val && val !== 'out-in' && val !== 'in-out') {
@@ -18,7 +19,7 @@ export default {
   },
   render () {
     const oldChild = this._vnode
-    const newChild = this.$slots.default[0]
+    const newChild = this.child
     if (oldChild && oldChild.data && (
       oldChild.tag !== newChild.tag ||
       oldChild.key !== newChild.key
@@ -26,25 +27,20 @@ export default {
       if (this.mode === 'out-in') {
         // return empty node
         // and queue an update when the leave finishes
-        addHook(oldChild, 'afterLeave', () => {
+        return addHook(oldChild, 'afterLeave', () => {
           this.$forceUpdate()
         })
-        return
-      } else {
-        if (this.mode === 'in-out') {
-          let delayedLeave
-          const performLeave = () => { delayedLeave() }
-          addHook(newChild, 'afterEnter', performLeave)
-          addHook(newChild, 'enterCancelled', performLeave)
-          addHook(oldChild, 'delayLeave', leave => {
-            delayedLeave = leave
-          })
-        }
-        return newChild
+      } else if (this.mode === 'in-out') {
+        let delayedLeave
+        const performLeave = () => { delayedLeave() }
+        addHook(newChild, 'afterEnter', performLeave)
+        addHook(newChild, 'enterCancelled', performLeave)
+        addHook(oldChild, 'delayLeave', leave => {
+          delayedLeave = leave
+        })
       }
-    } else {
-      return newChild
     }
+    return newChild
   }
 }