Skip to content

Commit

Permalink
support transition on component with v-show in root node (fix #3431)
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Aug 15, 2016
1 parent 174e936 commit aab560e
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 7 deletions.
34 changes: 27 additions & 7 deletions src/platforms/web/runtime/directives/show.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,36 @@
import { isIE9 } from 'web/util/index'
import { enter, leave } from '../modules/transition'

// recursively search for possible transition defined inside the component root
function locateNode (vnode: VNode): VNodeWithData {
return vnode.child && (!vnode.data || !vnode.data.transition)
? locateNode(vnode.child._vnode)
: vnode
// The v-show directive may appear on a component's parent vnode or its
// inner vnode, and the transition wrapper may be defined outside or inside
// the component. To cater for all possible cases, recursively search for
// possible transition defined on component parent placeholder or inside
// child component.
function detectTransitionNode (vnode: VNode): VNodeWithData {
let parent = vnode
while ((parent = parent.parent)) {
if (hasTransition(parent)) {
return parent
}
}
if (hasTransition(vnode)) {
return vnode
}
while (vnode.child && (vnode = vnode.child._vnode)) {
if (hasTransition(vnode)) {
return vnode
}
}
return vnode
}

function hasTransition (vnode) {
return vnode.data && vnode.data.transition
}

export default {
bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {
vnode = locateNode(vnode)
vnode = detectTransitionNode(vnode)
const transition = vnode.data && vnode.data.transition
if (value && transition && transition.appear && !isIE9) {
enter(vnode)
Expand All @@ -24,7 +44,7 @@ export default {
update (el: any, { value, oldValue }: VNodeDirective, vnode: VNodeWithData) {
/* istanbul ignore if */
if (value === oldValue) return
vnode = locateNode(vnode)
vnode = detectTransitionNode(vnode)
const transition = vnode.data && vnode.data.transition
if (transition && !isIE9) {
if (value) {
Expand Down
39 changes: 39 additions & 0 deletions test/unit/features/transition/transition.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,45 @@ if (!isIE9) {
}).then(done)
})

fit('transition with v-show, with transition outside and v-show inside', done => {
const vm = new Vue({
template: `
<div>
<transition name="test">
<test :ok="ok"></test>
</transition>
</div>
`,
data: { ok: true },
components: {
test: {
props: ['ok'],
template: `<div v-show="ok" class="test">foo</div>`
}
}
}).$mount(el)

// should not apply transition on initial render by default
expect(vm.$el.textContent).toBe('foo')
expect(vm.$el.children[0].style.display).toBe('')
vm.ok = false
waitForUpdate(() => {
expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
}).thenWaitFor(nextFrame).then(() => {
expect(vm.$el.children[0].className).toBe('test test-leave-active')
}).thenWaitFor(duration + 10).then(() => {
expect(vm.$el.children[0].style.display).toBe('none')
vm.ok = true
}).then(() => {
expect(vm.$el.children[0].style.display).toBe('')
expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
}).thenWaitFor(nextFrame).then(() => {
expect(vm.$el.children[0].className).toBe('test test-enter-active')
}).thenWaitFor(duration + 10).then(() => {
expect(vm.$el.children[0].className).toBe('test')
}).then(done)
})

it('leaveCancelled (v-show only)', done => {
const spy = jasmine.createSpy('leaveCancelled')
const vm = new Vue({
Expand Down

0 comments on commit aab560e

Please sign in to comment.