I'm seeing some behavior with Vue transitions that I don't understand. It'll be easier to explain by showing an example:
Given the following component:
<transition :name="transitionName">
<div v-if="showMe">Hey</div>
</transition>
<button @click="transitionName='slide-left'; showMe = false">Left</button>
And that the following is true:
- There are css classes in place for the transition names
.slide-left
and.slide-right
which does what their names imply. - The initial state of
transitionName
isslide-right
- The initial state of
showMe
is true
I would expect the div to slide left when the button is clicked. However, it slides right.
A full reproducible is available here:
var demo = new Vue({
el: '#demo',
data: {
showMe: true,
transitionName: 'slide-right'
}
});
#demo {
display: flex;
justify-content: center;
flex-direction: column;
width: 20%;
margin: 100px auto;
text-align: center;
}
.buttons {
display: flex;
justify-content: space-between;
}
.slide-right-enter-active,
.slide-left-enter-active,
.slide-right-leave-active,
.slide-left-leave-active {
transition: all 1s ease-in-out;
}
.slide-left-enter,
.slide-left-leave-to {
transform: translateX(-100%);
}
.slide-right-enter,
.slide-right-leave-to {
transform: translateX(100%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<transition :name="transitionName">
<div v-if="showMe">Hey</div>
</transition>
<div class="buttons">
<button @click="transitionName='slide-left'; showMe = false">left</button>
<button @click="transitionName='slide-right'; showMe = !showMe">right</button>
</div>
</div>
It contains both a "left" and "right" button, but the component will slide "right" regardless of which one you click.
I can fix it by changing the button's callback to this:
this.transitionName = 'slide-left';
Vue.nextTick(() => {
this.showMe = false;
});
But I'm wondering why nextTick
is necessary here, and whether there is a better way to solve the problem in general.
It's because of Vue's update cycle. It queues all the updates and 'flushes' them at the same time so it can evaluate which sections of the page need to be changed and only patch those changes. When you use
Vue.nextTick
you're essentially telling Vue to wait until the next update cycle before settingthis.showMe = false
.The docs explain it better than I do: