Routing transition animation changes
Route Transition Animation Variations
Route transition animations are a crucial means of enhancing user experience in Vue.js applications. Through well-designed animations, page transitions can become more natural and fluid, guiding user attention while maintaining application continuity. Vue Router seamlessly integrates with Vue's transition system, offering multiple ways to implement route transitions.
Basic Route Transition Implementation
The simplest route transition can be achieved using Vue's <transition>
component. When routes switch, Vue automatically adds enter/leave transition class names to the old and new components:
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
Corresponding CSS styles:
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
This basic transition suits most simple scenarios, where the transition
property can be adjusted to control animation duration, easing functions, and other parameters.
Dynamic Transition Effects
Different transition effects can be applied based on route navigation direction, requiring a combination of Vue Router's navigation guards and component state:
// router.js
const router = createRouter({
history: createWebHistory(),
routes: [...],
})
router.beforeEach((to, from) => {
const toDepth = to.meta.depth || 0
const fromDepth = from.meta.depth || 0
to.meta.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
})
Then use dynamic transition names in the component:
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transitionName || 'fade'">
<component :is="Component" />
</transition>
</router-view>
Corresponding CSS:
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
transition: all 0.5s ease;
}
.slide-left-enter-from {
transform: translateX(100%);
}
.slide-left-leave-to {
transform: translateX(-100%);
}
.slide-right-enter-from {
transform: translateX(-100%);
}
.slide-right-leave-to {
transform: translateX(100%);
}
Transition Control Based on Route Meta Information
The meta
field in routes allows finer control over transition behavior for each route:
const routes = [
{
path: '/',
component: Home,
meta: {
transition: 'zoom'
}
},
{
path: '/about',
component: About,
meta: {
transition: 'fade'
}
}
]
Usage in components:
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" />
</transition>
</router-view>
Combining Transitions and Animations
Vue's transition system supports using both CSS transitions and animations simultaneously, which is useful for more complex effects:
<transition
name="bounce"
enter-active-class="animate__animated animate__bounceIn"
leave-active-class="animate__animated animate__bounceOut"
>
<router-view />
</transition>
Here, the Animate.css library is used, but custom animations can also be created:
@keyframes slideIn {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes slideOut {
from { transform: translateY(0); opacity: 1; }
to { transform: translateY(-20px); opacity: 0; }
}
.slide-enter-active {
animation: slideIn 0.4s forwards;
}
.slide-leave-active {
animation: slideOut 0.4s forwards;
}
Composite Transitions for Lists and Routes
When route transitions involve list item changes, richer effects can be achieved by combining <transition-group>
:
<router-view v-slot="{ Component }">
<transition name="page" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
Inside child components:
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</transition-group>
Corresponding styles:
.page-enter-active, .page-leave-active {
transition: all 0.3s;
}
.page-enter-from, .page-leave-to {
opacity: 0;
transform: scale(0.95);
}
.list-move,
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
.list-leave-active {
position: absolute;
}
Complex Transitions Using JavaScript Hooks
For programmatically controlled complex transitions, JavaScript hooks can be used:
<router-view v-slot="{ Component }">
<transition
:css="false"
@before-enter="beforeEnter"
@enter="enter"
@leave="leave"
>
<component :is="Component" />
</transition>
</router-view>
JavaScript section:
methods: {
beforeEnter(el) {
el.style.opacity = 0
el.style.transform = 'scale(0.9)'
},
enter(el, done) {
gsap.to(el, {
opacity: 1,
scale: 1,
duration: 0.5,
ease: 'power2.out',
onComplete: done
})
},
leave(el, done) {
gsap.to(el, {
opacity: 0,
scale: 1.1,
duration: 0.3,
ease: 'power2.in',
onComplete: done
})
}
}
Here, the GSAP library is used for finer animation control, but the native Web Animations API can also be used.
Performance Optimization for Route Transitions
Complex route transitions may impact application performance, so the following points should be noted:
- Use CSS hardware acceleration whenever possible:
.transform-layer {
will-change: transform;
backface-visibility: hidden;
perspective: 1000px;
}
- Avoid animating too many elements simultaneously; use the
appear
attribute to control initial render animations:
<transition appear @before-appear="customBeforeAppear">
<!-- content -->
</transition>
- For complex scenarios, consider using
<keep-alive>
to cache component state:
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<keep-alive>
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
Handling Nested Route Transitions
Nested routes require special handling of transition effects to ensure coordination between parent and child route animations:
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" />
</transition>
</router-view>
In child route components:
<router-view v-slot="{ Component }" class="child-view">
<transition name="slide-up">
<component :is="Component" />
</transition>
</router-view>
Corresponding styles should ensure correct hierarchy:
.child-view {
position: absolute;
top: 0;
left: 0;
right: 0;
}
.slide-up-enter-active,
.slide-up-leave-active {
transition: all 0.3s ease-out;
}
.slide-up-enter-from {
transform: translateY(20px);
opacity: 0;
}
.slide-up-leave-to {
transform: translateY(-20px);
opacity: 0;
}
Combining Route Transitions with State Management
Storing transition states in Vuex or Pinia enables global unified transition control:
// store/transition.js
export const useTransitionStore = defineStore('transition', {
state: () => ({
type: 'fade',
duration: 300
}),
actions: {
setTransition(payload) {
this.type = payload.type
this.duration = payload.duration
}
}
})
Usage in components:
<script setup>
import { useTransitionStore } from '@/stores/transition'
const transition = useTransitionStore()
</script>
<template>
<router-view v-slot="{ Component }">
<transition
:name="transition.type"
:duration="transition.duration"
mode="out-in"
>
<component :is="Component" />
</transition>
</router-view>
</template>
Responsive Route Transitions
Dynamically adjust transitions based on viewport size or user preferences:
// Detect user preference
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches
// In components
const transitionName = ref(prefersReducedMotion ? 'fade' : 'slide')
watch(() => route.path, () => {
if (prefersReducedMotion) return
// Dynamically adjust transitions based on route changes
if (route.path === '/about') {
transitionName.value = 'zoom'
} else {
transitionName.value = 'slide'
}
})
Advanced Route Transition Patterns
For scenarios requiring more complex control, combine Vue's render functions with custom directives:
app.directive('route-transition', {
mounted(el, binding) {
const { value } = binding
el.style.transition = `all ${value.duration}ms ${value.easing}`
},
updated(el, binding) {
const { value, oldValue } = binding
if (value.active !== oldValue.active) {
if (value.active) {
el.classList.add('enter-active')
el.classList.remove('leave-active')
} else {
el.classList.add('leave-active')
el.classList.remove('enter-active')
}
}
}
})
Using custom transition components:
const RouteTransition = {
functional: true,
render(h, { children }) {
const data = {
props: {
name: 'custom-transition',
mode: 'out-in'
},
on: {
beforeEnter(el) {
// Custom logic
},
afterEnter(el) {
// Custom logic
}
}
}
return h('transition', data, children)
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn