Skip to content

Commit 0d6cbff

Browse files
jkzingztlevi
authored andcommitted
fix(transition): consider async placeholder as valid child to return (vuejs#6369)
fix vuejs#6256
1 parent c69efbb commit 0d6cbff

File tree

5 files changed

+97
-6
lines changed

5 files changed

+97
-6
lines changed

src/core/vdom/helpers/get-first-component-child.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/* @flow */
22

33
import { isDef } from 'shared/util'
4+
import { isAsyncPlaceholder } from './is-async-placeholder'
45

56
export function getFirstComponentChild (children: ?Array<VNode>): ?VNode {
67
if (Array.isArray(children)) {
78
for (let i = 0; i < children.length; i++) {
89
const c = children[i]
9-
if (isDef(c) && isDef(c.componentOptions)) {
10+
if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
1011
return c
1112
}
1213
}

src/core/vdom/helpers/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export * from './update-listeners'
66
export * from './normalize-children'
77
export * from './resolve-async-component'
88
export * from './get-first-component-child'
9+
export * from './is-async-placeholder'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/* @flow */
2+
3+
export function isAsyncPlaceholder (node: VNode): boolean {
4+
return node.isComment && node.asyncFactory
5+
}

src/platforms/web/runtime/components/transition.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55

66
import { warn } from 'core/util/index'
77
import { camelize, extend, isPrimitive } from 'shared/util'
8-
import { mergeVNodeHook, getFirstComponentChild } from 'core/vdom/helpers/index'
8+
import {
9+
mergeVNodeHook,
10+
isAsyncPlaceholder,
11+
getFirstComponentChild
12+
} from 'core/vdom/helpers/index'
913

1014
export const transitionProps = {
1115
name: String,
@@ -72,10 +76,6 @@ function isSameChild (child: VNode, oldChild: VNode): boolean {
7276
return oldChild.key === child.key && oldChild.tag === child.tag
7377
}
7478

75-
function isAsyncPlaceholder (node: VNode): boolean {
76-
return node.isComment && node.asyncFactory
77-
}
78-
7979
export default {
8080
name: 'transition',
8181
props: transitionProps,

test/unit/features/component/component-keep-alive.spec.js

+84
Original file line numberDiff line numberDiff line change
@@ -862,5 +862,89 @@ describe('Component keep-alive', () => {
862862
)
863863
}).then(done)
864864
})
865+
866+
it('async components with transition-mode out-in', done => {
867+
const barResolve = jasmine.createSpy('bar resolved')
868+
let next
869+
const foo = (resolve) => {
870+
setTimeout(() => {
871+
resolve(one)
872+
Vue.nextTick(next)
873+
}, duration / 2)
874+
}
875+
const bar = (resolve) => {
876+
setTimeout(() => {
877+
resolve(two)
878+
barResolve()
879+
}, duration / 2)
880+
}
881+
components = {
882+
foo,
883+
bar
884+
}
885+
const vm = new Vue({
886+
template: `<div>
887+
<transition name="test" mode="out-in" @after-enter="afterEnter" @after-leave="afterLeave">
888+
<keep-alive>
889+
<component :is="view" class="test"></component>
890+
</keep-alive>
891+
</transition>
892+
</div>`,
893+
data: {
894+
view: 'foo'
895+
},
896+
components,
897+
methods: {
898+
afterEnter () {
899+
next()
900+
},
901+
afterLeave () {
902+
next()
903+
}
904+
}
905+
}).$mount(el)
906+
expect(vm.$el.textContent).toBe('')
907+
next = () => {
908+
assertHookCalls(one, [1, 1, 1, 0, 0])
909+
assertHookCalls(two, [0, 0, 0, 0, 0])
910+
waitForUpdate(() => {
911+
expect(vm.$el.innerHTML).toBe(
912+
'<div class="test test-enter test-enter-active">one</div>'
913+
)
914+
}).thenWaitFor(nextFrame).then(() => {
915+
expect(vm.$el.innerHTML).toBe(
916+
'<div class="test test-enter-active test-enter-to">one</div>'
917+
)
918+
}).thenWaitFor(_next => { next = _next }).then(() => {
919+
// foo afterEnter get called
920+
expect(vm.$el.innerHTML).toBe('<div class="test">one</div>')
921+
vm.view = 'bar'
922+
}).thenWaitFor(nextFrame).then(() => {
923+
assertHookCalls(one, [1, 1, 1, 1, 0])
924+
assertHookCalls(two, [0, 0, 0, 0, 0])
925+
expect(vm.$el.innerHTML).toBe(
926+
'<div class="test test-leave-active test-leave-to">one</div><!---->'
927+
)
928+
}).thenWaitFor(_next => { next = _next }).then(() => {
929+
// foo afterLeave get called
930+
// and bar has already been resolved before afterLeave get called
931+
expect(barResolve.calls.count()).toBe(1)
932+
expect(vm.$el.innerHTML).toBe('<!---->')
933+
}).thenWaitFor(nextFrame).then(() => {
934+
expect(vm.$el.innerHTML).toBe(
935+
'<div class="test test-enter test-enter-active">two</div>'
936+
)
937+
assertHookCalls(one, [1, 1, 1, 1, 0])
938+
assertHookCalls(two, [1, 1, 1, 0, 0])
939+
}).thenWaitFor(nextFrame).then(() => {
940+
expect(vm.$el.innerHTML).toBe(
941+
'<div class="test test-enter-active test-enter-to">two</div>'
942+
)
943+
}).thenWaitFor(_next => { next = _next }).then(() => {
944+
// bar afterEnter get called
945+
expect(vm.$el.innerHTML).toBe('<div class="test">two</div>')
946+
}).then(done)
947+
}
948+
})
865949
}
866950
})

0 commit comments

Comments
 (0)