Ver código fonte

support transitions on v-show

Evan You 10 anos atrás
pai
commit
e1f48a6134

+ 0 - 2
src/compiler/codegen/directives/index.js

@@ -1,5 +1,4 @@
 import { model } from './model'
-import { show } from './show'
 import { text } from './text'
 import { html } from './html'
 import { ref } from './ref'
@@ -7,7 +6,6 @@ export { genHandlers } from './on'
 
 export const directives = {
   model,
-  show,
   text,
   html,
   ref,

+ 0 - 8
src/compiler/codegen/directives/show.js

@@ -1,8 +0,0 @@
-import { addStyleBinding } from '../../helpers'
-
-export function show (el, dir) {
-  addStyleBinding(el, 'display', `(${dir.value}?'':'none')`)
-  if (el.elseBlock) {
-    addStyleBinding(el.elseBlock, 'display', `(${dir.value}?'none':'')`)
-  }
-}

+ 5 - 0
src/compiler/codegen/index.js

@@ -95,6 +95,11 @@ function genData (el) {
   if (el.transition != null) {
     data += `transition:__resolveTransition__(${el.transition}),`
   }
+  // v-show, used to avoid transition being applied
+  // since v-show takes it over
+  if (el.attrsMap['v-show'] || el.show) {
+    data += 'show:true,'
+  }
   // props
   if (el.props) {
     data += `props:{${genProps(el.props)}},`

+ 10 - 2
src/compiler/parser/index.js

@@ -229,8 +229,16 @@ function processIf (el) {
 function processElse (el, parent) {
   const prev = findPrevElement(parent.children)
   if (prev && (prev.if || prev.attrsMap['v-show'])) {
-    prev.elseBlock = el
-    if (!prev.if) {
+    if (prev.if) {
+      // v-if
+      prev.elseBlock = el
+    } else {
+      // v-show: simply add a v-show with reversed value
+      addDirective(el, 'show', `!(${prev.attrsMap['v-show']})`)
+      // also copy its transition
+      el.transition = prev.transition
+      // als set show to true
+      el.show = true
       parent.children.push(el)
     }
   } else if (process.env.NODE_ENV !== 'production') {

+ 3 - 1
src/runtime/directives/index.js

@@ -1,5 +1,7 @@
 import model from './model'
+import show from './show'
 
 export default {
-  model
+  model,
+  show
 }

+ 25 - 0
src/runtime/directives/show.js

@@ -0,0 +1,25 @@
+import transitionHooks from '../vdom-web/modules/transition'
+
+const beforeEnter = transitionHooks.create
+const onLeave = transitionHooks.remove
+
+export default {
+  bind (el, value) {
+    el.style.display = value ? '' : 'none'
+  },
+  update (el, value, _, vnode) {
+    const transition = vnode.data.transition
+    if (transition != null && beforeEnter) {
+      if (value) {
+        beforeEnter(null, vnode, true /* force */)
+        el.style.display = ''
+      } else {
+        onLeave(vnode, () => {
+          el.style.display = 'none'
+        }, true /* force */)
+      }
+    } else {
+      el.style.display = value ? '' : 'none'
+    }
+  }
+}

+ 41 - 14
src/runtime/vdom-web/modules/transition.js

@@ -29,14 +29,23 @@ function nextFrame (fn) {
   })
 }
 
-function beforeEnter (_, vnode) {
+function beforeEnter (_, vnode, force) {
   // if this is a component root node and the compoennt's
   // parent container node also has transition, skip.
   if (vnode.parent && vnode.parent.data.transition) {
     return
   }
+  // let v-show handle this
+  if (vnode.data.show && !force) {
+    return
+  }
 
   const el = vnode.elm
+  // call leave callback now
+  if (el._leaveCb) {
+    el._leaveCb.cancelled = true
+    el._leaveCb()
+  }
   const data = vnode.data.transition
   if (data == null) {
     return
@@ -52,12 +61,7 @@ function beforeEnter (_, vnode) {
   } = detectAuto(data)
 
   const userWantsControl = enter && enter.length > 1
-  const cb = el._enterCb = () => {
-    // ensure only called once
-    if (cb.called) {
-      return
-    }
-    cb.called = true
+  const cb = el._enterCb = once(() => {
     if (enterActiveClass) {
       removeTransitionClass(el, enterActiveClass)
     }
@@ -67,7 +71,7 @@ function beforeEnter (_, vnode) {
       afterEnter && afterEnter(el)
     }
     el._enterCb = null
-  }
+  })
 
   beforeEnter && beforeEnter(el)
   if (enterClass) {
@@ -90,12 +94,16 @@ function beforeEnter (_, vnode) {
   }
 }
 
-function onLeave (vnode, rm) {
+function onLeave (vnode, rm, force) {
   // if this is a component root node and the compoennt's
   // parent container node also has transition, skip.
   if (vnode.parent && vnode.parent.data.transition) {
     return
   }
+  // let v-show handle this
+  if (vnode.data.show && !force) {
+    return
+  }
 
   const el = vnode.elm
   // call enter callback now
@@ -113,14 +121,23 @@ function onLeave (vnode, rm) {
     leaveActiveClass,
     beforeLeave,
     leave,
-    afterLeave
+    afterLeave,
+    leaveCancelled
   } = detectAuto(data)
 
   const userWantsControl = leave && leave.length > 1
-  const cb = () => {
-    rm()
-    afterLeave && afterLeave(el)
-  }
+  const cb = el._leaveCb = once(() => {
+    if (leaveActiveClass) {
+      removeTransitionClass(el, leaveActiveClass)
+    }
+    if (cb.cancelled) {
+      leaveCancelled && leaveCancelled(el)
+    } else {
+      rm()
+      afterLeave && afterLeave(el)
+    }
+    el._leaveCb = null
+  })
 
   beforeLeave && beforeLeave(el)
   if (leaveClass) {
@@ -228,6 +245,16 @@ function toMs (s) {
   return Number(s.slice(0, -1)) * 1000
 }
 
+function once (fn) {
+  let called = false
+  return () => {
+    if (!called) {
+      called = true
+      fn()
+    }
+  }
+}
+
 export default !transitionEndEvent ? {} : {
   create: beforeEnter,
   remove: onLeave