路由过渡动画变化
路由过渡动画变化
路由过渡动画是Vue.js应用中提升用户体验的重要手段。通过合理的动画设计,可以让页面切换更加自然流畅,引导用户注意力,同时保持应用的连贯性。Vue Router与Vue的过渡系统完美结合,提供了多种实现路由过渡的方式。
基础路由过渡实现
最简单的路由过渡可以通过Vue的<transition>
组件实现。当路由切换时,Vue会自动为旧组件和新组件添加进入/离开的过渡类名:
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
对应的CSS样式:
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
这种基础过渡适合大多数简单场景,通过调整transition
属性可以控制动画的持续时间、缓动函数等参数。
动态过渡效果
根据不同的路由切换方向,可以应用不同的过渡效果。这需要结合Vue Router的导航守卫和组件的状态:
// 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'
})
然后在组件中使用动态过渡名称:
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transitionName || 'fade'">
<component :is="Component" />
</transition>
</router-view>
对应的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%);
}
基于路由元信息的过渡控制
通过路由的meta字段可以更精细地控制每个路由的过渡行为:
const routes = [
{
path: '/',
component: Home,
meta: {
transition: 'zoom'
}
},
{
path: '/about',
component: About,
meta: {
transition: 'fade'
}
}
]
组件中使用:
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" />
</transition>
</router-view>
组合过渡与动画
Vue的过渡系统支持同时使用CSS过渡和动画,这在需要更复杂效果时非常有用:
<transition
name="bounce"
enter-active-class="animate__animated animate__bounceIn"
leave-active-class="animate__animated animate__bounceOut"
>
<router-view />
</transition>
这里使用了Animate.css库,但也可以自定义动画:
@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;
}
列表与路由的复合过渡
当路由切换涉及列表项变化时,可以结合<transition-group>
实现更丰富的效果:
<router-view v-slot="{ Component }">
<transition name="page" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
在子组件内部:
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</transition-group>
对应的样式:
.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;
}
JavaScript钩子实现复杂过渡
对于需要程序控制的复杂过渡,可以使用JavaScript钩子:
<router-view v-slot="{ Component }">
<transition
:css="false"
@before-enter="beforeEnter"
@enter="enter"
@leave="leave"
>
<component :is="Component" />
</transition>
</router-view>
JavaScript部分:
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
})
}
}
这里使用了GSAP库来实现更精细的动画控制,但也可以使用原生Web Animations API。
路由过渡的性能优化
复杂的路由过渡可能影响应用性能,需要注意以下几点:
- 尽量使用CSS硬件加速:
.transform-layer {
will-change: transform;
backface-visibility: hidden;
perspective: 1000px;
}
- 避免同时动画过多元素,可以使用
appear
属性控制初始渲染动画:
<transition appear @before-appear="customBeforeAppear">
<!-- 内容 -->
</transition>
- 对于复杂场景,考虑使用
<keep-alive>
缓存组件状态:
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<keep-alive>
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
嵌套路由的过渡处理
嵌套路由需要特殊处理过渡效果,以确保父子路由的动画协调:
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" />
</transition>
</router-view>
在子路由组件中:
<router-view v-slot="{ Component }" class="child-view">
<transition name="slide-up">
<component :is="Component" />
</transition>
</router-view>
对应的样式需要确保层级关系正确:
.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;
}
路由过渡与状态管理结合
将过渡状态存储在Vuex或Pinia中可以实现全局统一的过渡控制:
// store/transition.js
export const useTransitionStore = defineStore('transition', {
state: () => ({
type: 'fade',
duration: 300
}),
actions: {
setTransition(payload) {
this.type = payload.type
this.duration = payload.duration
}
}
})
组件中使用:
<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>
响应式路由过渡
根据视口大小或用户偏好动态调整过渡效果:
// 检测用户偏好
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches
// 在组件中
const transitionName = ref(prefersReducedMotion ? 'fade' : 'slide')
watch(() => route.path, () => {
if (prefersReducedMotion) return
// 根据路由变化动态调整过渡
if (route.path === '/about') {
transitionName.value = 'zoom'
} else {
transitionName.value = 'slide'
}
})
高级路由过渡模式
对于需要更复杂控制的场景,可以结合Vue的渲染函数和自定义指令:
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')
}
}
}
})
使用自定义过渡组件:
const RouteTransition = {
functional: true,
render(h, { children }) {
const data = {
props: {
name: 'custom-transition',
mode: 'out-in'
},
on: {
beforeEnter(el) {
// 自定义逻辑
},
afterEnter(el) {
// 自定义逻辑
}
}
}
return h('transition', data, children)
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn