You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
3.1 KiB
Vue

<template>
<transition
:name="transitionName"
:mode="transitionMode"
:enter-active-class="transitionEnterActiveClass"
@beforeLeave="beforeLeave"
@enter="enter"
@afterEnter="afterEnter"
>
<slot />
</transition>
</template>
<script>
const DEFAULT_TRANSITION = `fade`;
const DEFAULT_TRANSITION_MODE = `out-in`;
export default {
name: `TransitionPage`,
data() {
return {
prevHeight: 0,
transitionName: DEFAULT_TRANSITION,
transitionMode: DEFAULT_TRANSITION_MODE,
transitionEnterActiveClass: ``
};
},
created() {
this.$router.beforeEach((to, from, next) => {
let transitionName =
to.meta.transitionName ||
from.meta.transitionName ||
DEFAULT_TRANSITION;
if (transitionName === `slide`) {
const toDepth = to.path.split(`/`).length;
const fromDepth = from.path.split(`/`).length;
transitionName = toDepth < fromDepth ? `slide-right` : `slide-left`;
}
this.transitionMode = DEFAULT_TRANSITION_MODE;
this.transitionEnterActiveClass = `${transitionName}-enter-active`;
if (to.meta.transitionName === `zoom`) {
this.transitionMode = `in-out`;
this.transitionEnterActiveClass = `zoom-enter-active`;
document.body.style.overflow = `hidden`;
}
if (from.meta.transitionName === `zoom`) {
this.transitionMode = null;
this.transitionEnterActiveClass = null;
document.body.style.overflow = null;
}
this.transitionName = transitionName;
next();
});
},
methods: {
beforeLeave(element) {
this.prevHeight = getComputedStyle(element).height;
},
enter(element) {
const { height } = getComputedStyle(element);
// eslint-disable-next-line no-param-reassign
element.style.height = this.prevHeight;
setTimeout(() => {
// eslint-disable-next-line no-param-reassign
element.style.height = height;
});
},
afterEnter(element) {
// eslint-disable-next-line no-param-reassign
element.style.height = `auto`;
}
}
};
</script>
<style lang="scss">
.fade-enter-active,
.fade-leave-active {
transition-duration: 0.3s;
transition-property: height, opacity;
transition-timing-function: ease;
overflow: hidden;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
transition-duration: 0.5s;
transition-property: height, opacity, transform;
transition-timing-function: cubic-bezier(0.55, 0, 0.1, 1);
overflow: hidden;
}
.slide-left-enter,
.slide-right-leave-active {
opacity: 0;
transform: translate(2em, 0);
}
.slide-left-leave-active,
.slide-right-enter {
opacity: 0;
transform: translate(-2em, 0);
}
.zoom-enter-active,
.zoom-leave-active {
animation-duration: 0.5s;
animation-fill-mode: both;
animation-name: zoom;
}
.zoom-leave-active {
animation-direction: reverse;
}
@keyframes zoom {
from {
opacity: 0;
transform: scale3d(0.3, 0.3, 0.3);
}
100% {
opacity: 1;
}
}
</style>