At NOVA LAB, transitioning between station sections — from the command center to the laboratory, from the reactor to the hangar — should be smooth and natural. Vue Router supports transition animations between pages thanks to its integration with the
<Transition> component.To animate router view changes, you use the slot API on
<RouterView>. Vue Router provides the current component as a slot variable:1<RouterView v-slot="{ Component }">
2 <Transition name="page" mode="out-in">
3 <component :is="Component" />
4 </Transition>
5</RouterView>Here's how it works step by step:
<RouterView v-slot="{ Component }"> — the router provides the current page component as Component<Transition name="page" mode="out-in"> — you wrap the dynamic component in a Transition<component :is="Component" /> — you render the dynamic page componentThree key rules:
v-slot="{ Component }" — you cannot directly wrap <RouterView> in <Transition> (this won't work in Vue 3)mode="out-in" — without it, the old and new pages will animate simultaneously, which looks chaotic:key on <component> — Vue Router automatically reacts to route changesThe corresponding CSS classes:
1.page-enter-active,
2.page-leave-active {
3 transition: all 0.3s ease;
4}
5
6.page-enter-from {
7 opacity: 0;
8 transform: translateX(20px);
9}
10
11.page-leave-to {
12 opacity: 0;
13 transform: translateX(-20px);
14}Each section of the NOVA LAB station can have a different animation type — the command center slides in from the left, the alerts panel pops up from below. Use the
meta field in the route definition to assign an animation name:1const routes = [
2 {
3 path: '/dashboard',
4 component: Dashboard,
5 meta: { transition: 'slide-left' }
6 },
7 {
8 path: '/settings',
9 component: Settings,
10 meta: { transition: 'slide-right' }
11 },
12 {
13 path: '/alerts',
14 component: Alerts,
15 meta: { transition: 'slide-up' }
16 }
17]In the template, read the animation name from the
route object:1<RouterView v-slot="{ Component, route }">
2 <Transition :name="route.meta.transition || 'fade'" mode="out-in">
3 <component :is="Component" />
4 </Transition>
5</RouterView>Note the
|| 'fade' — this is a fallback for routes without a defined animation. The v-slot gives you access to both Component (the current page component) and route (the route object with meta data).You can change the animation depending on whether the user is navigating "forward" or "backward":
1<script setup>
2import { ref } from 'vue'
3import { useRouter } from 'vue-router'
4
5const transitionName = ref('slide-left')
6const router = useRouter()
7
8router.beforeEach((to, from) => {
9 // Compare page depths to determine direction
10 const toDepth = to.path.split('/').length
11 const fromDepth = from.path.split('/').length
12
13 transitionName.value = toDepth < fromDepth ? 'slide-right' : 'slide-left'
14})
15</script>
16
17<template>
18 <RouterView v-slot="{ Component }">
19 <Transition :name="transitionName" mode="out-in">
20 <component :is="Component" />
21 </Transition>
22 </RouterView>
23</template>You can combine Transition with KeepAlive to cache page views. This is useful when the user frequently switches between the same station sections and you don't want to lose state (e.g., scroll position, entered data):
1<RouterView v-slot="{ Component }">
2 <Transition name="fade" mode="out-in">
3 <KeepAlive :max="5">
4 <component :is="Component" />
5 </KeepAlive>
6 </Transition>
7</RouterView>The order matters —
<Transition> on the outside, <KeepAlive> on the inside. The :max="5" attribute limits the number of cached components to avoid excessive memory usage.opacity and transform — these properties are GPU-accelerated