test in-out early cancel with keep-alive

This commit is contained in:
Evan You 2016-07-14 12:26:31 -04:00
parent ccf3a61532
commit 210a3a22b0
4 changed files with 72 additions and 7 deletions

View File

@ -2,7 +2,7 @@
// supports transition mode (out-in / in-out) // supports transition mode (out-in / in-out)
import { warn } from 'core/util/index' import { warn } from 'core/util/index'
import { noop, camelize } from 'shared/util' import { camelize } from 'shared/util'
import { getRealChild, mergeVNodeHook } from 'core/vdom/helpers' import { getRealChild, mergeVNodeHook } from 'core/vdom/helpers'
export const transitionProps = { export const transitionProps = {
@ -110,16 +110,11 @@ export default {
} else if (mode === 'in-out') { } else if (mode === 'in-out') {
let delayedLeave let delayedLeave
const performLeave = () => { delayedLeave() } const performLeave = () => { delayedLeave() }
mergeVNodeHook(data, 'afterEnter', performLeave) mergeVNodeHook(data, 'afterEnter', performLeave)
mergeVNodeHook(data, 'enterCancelled', performLeave) mergeVNodeHook(data, 'enterCancelled', performLeave)
mergeVNodeHook(oldData, 'delayLeave', leave => { mergeVNodeHook(oldData, 'delayLeave', leave => {
delayedLeave = leave delayedLeave = leave
}) })
mergeVNodeHook(oldData, 'leaveCancelled', () => {
delayedLeave = noop
})
} }
} }

View File

@ -160,6 +160,10 @@ export function leave (vnode: VNodeWithData, rm: Function) {
} }
function performLeave () { function performLeave () {
// the delayed leave may have already been cancelled
if (cb.cancelled) {
return
}
// record leaving element // record leaving element
if (!vnode.data.show) { if (!vnode.data.show) {
(el.parentNode._pending || (el.parentNode._pending = {}))[vnode.key] = vnode (el.parentNode._pending || (el.parentNode._pending = {}))[vnode.key] = vnode

View File

@ -260,5 +260,71 @@ describe('Component keep-alive', () => {
assertHookCalls(two, [1, 1, 1, 1, 0]) assertHookCalls(two, [1, 1, 1, 1, 0])
}).then(done) }).then(done)
}) })
it('dynamic components, in-out with early cancel', done => {
let next
const vm = new Vue({
template: `<div>
<transition name="test" mode="in-out" @after-enter="afterEnter">
<component :is="view" class="test" keep-alive></component>
</transition>
</div>`,
data: { view: 'one' },
components,
methods: {
afterEnter () {
next()
}
}
}).$mount(el)
expect(vm.$el.textContent).toBe('one')
vm.view = 'two'
waitForUpdate(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test">one</div>' +
'<div class="test test-enter test-enter-active">two</div>'
)
}).thenWaitFor(nextFrame).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test">one</div>' +
'<div class="test test-enter-active">two</div>'
)
// switch again before enter finishes,
// this cancels both enter and leave.
vm.view = 'one'
}).then(() => {
// 1. the pending leaving "one" should be removed instantly.
// 2. the entering "two" should be placed into its final state instantly.
// 3. a new "one" is created and entering
expect(vm.$el.innerHTML).toBe(
'<div class="test">two</div>' +
'<div class="test test-enter test-enter-active">one</div>'
)
}).thenWaitFor(nextFrame).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test">two</div>' +
'<div class="test test-enter-active">one</div>'
)
}).thenWaitFor(_next => { next = _next }).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test">two</div>' +
'<div class="test">one</div>'
)
}).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test test-leave test-leave-active">two</div>' +
'<div class="test">one</div>'
)
}).thenWaitFor(nextFrame).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test test-leave-active">two</div>' +
'<div class="test">one</div>'
)
}).thenWaitFor(duration + 10).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test">one</div>'
)
}).then(done).then(done)
})
} }
}) })

View File

@ -142,7 +142,7 @@ if (!isIE9) {
}).then(done) }).then(done)
}) })
it('dynamic components, in-out with leaveCancell', done => { it('dynamic components, in-out with early cancel', done => {
let next let next
const vm = new Vue({ const vm = new Vue({
template: `<div> template: `<div>