You can achieve that by using CSS Animations and Vue Transition.
First, separate your overlay and content into different transitions:
<template lang="pug">
div
transition(name="overlay")
.DrawerMenu-Overlay(v-if="displayFlag")
transition(name="content")
.DrawerMenu-Body(v-if="displayFlag") Drawer menu
</template>
Then define your animations:
.DrawerMenu {
&-Overlay {
...
display: none;
}
...
}
.overlay-enter-active {
display: block;
animation: fade-in-and-slide-down 2s;
}
.content-enter-active {
animation: wait-and-fade-in 3s;
}
.content-leave-active {
animation: fade-out 1s;
}
@keyframes fade-in-and-slide-down {
0% {
opacity: 0;
}
50% {
opacity: 1;
transform: translateY(0);
}
100% {
transform: translateY(100%);
}
}
@keyframes wait-and-fade-in {
0% {
opacity: 0;
}
66% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
Example in CodeSandbox.
Another solution is using JavaScript animation library (such as animejs) combine with Vue Transition Hooks. I would prefer this solution for a complex animation.
<template lang="pug">
transition(@enter='enter' @leave='leave')
div(v-if='displayFlag')
.DrawerMenu-Overlay(ref='overlay')
.DrawerMenu-Body(ref='content' @click="displayFlag = false") Drawer menu
</template>
import anime from "animejs";
...
methods: {
enter(el, done) {
anime
.timeline({
easing: "linear",
duration: 1000,
complete: done
})
.add({
targets: this.$refs.overlay,
opacity: [0, 1]
})
.add({
targets: this.$refs.overlay,
translateY: "100%"
})
.add({
targets: this.$refs.content,
opacity: [0, 1]
});
},
leave(el, done) {
anime({
targets: el,
duration: 2000,
opacity: 0,
complete: done
});
},
...
}
...
You can also use without transition component but you have to handle v-if variable by yourself.
Example in CodeSandbox.