Skip to content

Commit aab560e

Browse files
committed
support transition on component with v-show in root node (fix #3431)
1 parent 174e936 commit aab560e

File tree

2 files changed

+66
-7
lines changed

2 files changed

+66
-7
lines changed

src/platforms/web/runtime/directives/show.js

+27-7
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,36 @@
33
import { isIE9 } from 'web/util/index'
44
import { enter, leave } from '../modules/transition'
55

6-
// recursively search for possible transition defined inside the component root
7-
function locateNode (vnode: VNode): VNodeWithData {
8-
return vnode.child && (!vnode.data || !vnode.data.transition)
9-
? locateNode(vnode.child._vnode)
10-
: vnode
6+
// The v-show directive may appear on a component's parent vnode or its
7+
// inner vnode, and the transition wrapper may be defined outside or inside
8+
// the component. To cater for all possible cases, recursively search for
9+
// possible transition defined on component parent placeholder or inside
10+
// child component.
11+
function detectTransitionNode (vnode: VNode): VNodeWithData {
12+
let parent = vnode
13+
while ((parent = parent.parent)) {
14+
if (hasTransition(parent)) {
15+
return parent
16+
}
17+
}
18+
if (hasTransition(vnode)) {
19+
return vnode
20+
}
21+
while (vnode.child && (vnode = vnode.child._vnode)) {
22+
if (hasTransition(vnode)) {
23+
return vnode
24+
}
25+
}
26+
return vnode
27+
}
28+
29+
function hasTransition (vnode) {
30+
return vnode.data && vnode.data.transition
1131
}
1232

1333
export default {
1434
bind (el: any, { value }: VNodeDirective, vnode: VNodeWithData) {
15-
vnode = locateNode(vnode)
35+
vnode = detectTransitionNode(vnode)
1636
const transition = vnode.data && vnode.data.transition
1737
if (value && transition && transition.appear && !isIE9) {
1838
enter(vnode)
@@ -24,7 +44,7 @@ export default {
2444
update (el: any, { value, oldValue }: VNodeDirective, vnode: VNodeWithData) {
2545
/* istanbul ignore if */
2646
if (value === oldValue) return
27-
vnode = locateNode(vnode)
47+
vnode = detectTransitionNode(vnode)
2848
const transition = vnode.data && vnode.data.transition
2949
if (transition && !isIE9) {
3050
if (value) {

test/unit/features/transition/transition.spec.js

+39
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,45 @@ if (!isIE9) {
558558
}).then(done)
559559
})
560560

561+
fit('transition with v-show, with transition outside and v-show inside', done => {
562+
const vm = new Vue({
563+
template: `
564+
<div>
565+
<transition name="test">
566+
<test :ok="ok"></test>
567+
</transition>
568+
</div>
569+
`,
570+
data: { ok: true },
571+
components: {
572+
test: {
573+
props: ['ok'],
574+
template: `<div v-show="ok" class="test">foo</div>`
575+
}
576+
}
577+
}).$mount(el)
578+
579+
// should not apply transition on initial render by default
580+
expect(vm.$el.textContent).toBe('foo')
581+
expect(vm.$el.children[0].style.display).toBe('')
582+
vm.ok = false
583+
waitForUpdate(() => {
584+
expect(vm.$el.children[0].className).toBe('test test-leave test-leave-active')
585+
}).thenWaitFor(nextFrame).then(() => {
586+
expect(vm.$el.children[0].className).toBe('test test-leave-active')
587+
}).thenWaitFor(duration + 10).then(() => {
588+
expect(vm.$el.children[0].style.display).toBe('none')
589+
vm.ok = true
590+
}).then(() => {
591+
expect(vm.$el.children[0].style.display).toBe('')
592+
expect(vm.$el.children[0].className).toBe('test test-enter test-enter-active')
593+
}).thenWaitFor(nextFrame).then(() => {
594+
expect(vm.$el.children[0].className).toBe('test test-enter-active')
595+
}).thenWaitFor(duration + 10).then(() => {
596+
expect(vm.$el.children[0].className).toBe('test')
597+
}).then(done)
598+
})
599+
561600
it('leaveCancelled (v-show only)', done => {
562601
const spy = jasmine.createSpy('leaveCancelled')
563602
const vm = new Vue({

0 commit comments

Comments
 (0)