Skip to content

Commit

Permalink
prevent out-in transition to enter early when parent re-renders (fix #…
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Aug 14, 2016
1 parent 6a15602 commit 854ccce
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
18 changes: 14 additions & 4 deletions src/platforms/web/runtime/components/transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ export function extractTransitionData (comp: Component): Object {
return data
}

function placeholder (h, rawChild) {
return /\d-keep-alive$/.test(rawChild.tag)
? h('keep-alive')
: null
}

export default {
name: 'transition',
props: transitionProps,
Expand Down Expand Up @@ -101,6 +107,10 @@ export default {
return rawChild
}

if (this._leaving) {
return placeholder(h, rawChild)
}

child.key = child.key == null
? `__v${child.tag + this._uid}__`
: child.key
Expand All @@ -115,13 +125,13 @@ export default {

// handle transition mode
if (mode === 'out-in') {
// return empty node and queue update when leave finishes
// return placeholder node and queue update when leave finishes
this._leaving = true
mergeVNodeHook(oldData, 'afterLeave', () => {
this._leaving = false
this.$forceUpdate()
})
return /\d-keep-alive$/.test(rawChild.tag)
? h('keep-alive')
: null
return placeholder(h, rawChild)
} else if (mode === 'in-out') {
let delayedLeave
const performLeave = () => { delayedLeave() }
Expand Down
48 changes: 48 additions & 0 deletions test/unit/features/transition/transition-mode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,54 @@ if (!isIE9) {
}).then(done)
})

// #3440
it('dynamic components, out-in (with extra re-render)', done => {
let next
const vm = new Vue({
template: `<div>
<transition name="test" mode="out-in" @after-leave="afterLeave">
<component :is="view" class="test">
</component>
</transition>
</div>`,
data: { view: 'one' },
components,
methods: {
afterLeave () {
next()
}
}
}).$mount(el)
expect(vm.$el.textContent).toBe('one')
vm.view = 'two'
waitForUpdate(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test test-leave test-leave-active">one</div><!---->'
)
}).thenWaitFor(nextFrame).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test test-leave-active">one</div><!---->'
)
// Force re-render before the element finishes leaving
// this should not cause the incoming element to enter early
vm.$forceUpdate()
}).thenWaitFor(_next => { next = _next }).then(() => {
expect(vm.$el.innerHTML).toBe('<!---->')
}).thenWaitFor(nextFrame).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test test-enter test-enter-active">two</div>'
)
}).thenWaitFor(nextFrame).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test test-enter-active">two</div>'
)
}).thenWaitFor(duration + 10).then(() => {
expect(vm.$el.innerHTML).toBe(
'<div class="test">two</div>'
)
}).then(done)
})

it('dynamic components, in-out', done => {
let next
const vm = new Vue({
Expand Down

0 comments on commit 854ccce

Please sign in to comment.