1. 基础路由动画实现
<!-- App.vue -->
<template>
<!--
router-view 的 v-slot 可以获取到:
- Component:要渲染的组件
- route:当前路由信息
-->
<router-view v-slot="{ Component, route }">
<!--
transition 组件用于添加过渡效果
name:过渡效果的名称,对应 CSS 类名前缀
mode:过渡模式
- out-in:旧内容先消失,新内容再出现
- in-out:新内容先出现,旧内容再消失
-->
<transition
name="fade"
mode="out-in"
>
<!--
动态组件,用于渲染路由对应的组件
:key 可以强制组件重新渲染
-->
<component
:is="Component"
:key="route.path"
/>
</transition>
</router-view>
</template>
<style>
/* 进入和离开的过渡效果 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
/*
进入前和离开后的状态
opacity: 0 表示完全透明
*/
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
/*
进入后和离开前的状态
opacity: 1 表示完全不透明
*/
.fade-enter-to,
.fade-leave-from {
opacity: 1;
}
</style>
2. 多种过渡效果
<template>
<router-view v-slot="{ Component, route }">
<!-- 根据路由元信息选择不同的过渡效果 -->
<transition
:name="route.meta.transition || 'fade'"
mode="out-in"
>
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</template>
<style>
/* 1. 淡入淡出效果 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
/* 2. 滑动效果 */
.slide-enter-active,
.slide-leave-active {
transition: all 0.5s ease;
}
/* 从右侧滑入 */
.slide-enter-from {
transform: translateX(100%);
}
/* 向左侧滑出 */
.slide-leave-to {
transform: translateX(-100%);
}
/* 3. 缩放效果 */
.scale-enter-active,
.scale-leave-active {
transition: all 0.5s ease;
}
.scale-enter-from,
.scale-leave-to {
transform: scale(0.9);
opacity: 0;
}
</style>
3. 路由配置示例
// router/index.js
const routes = [
{
path: '/',
component: Home,
// 在路由元信息中指定过渡效果
meta: {
transition: 'fade',
// 可以指定更多配置
transitionMode: 'out-in',
transitionDuration: 500
}
},
{
path: '/about',
component: About,
meta: {
transition: 'slide'
}
},
{
path: '/contact',
component: Contact,
meta: {
transition: 'scale'
}
}
]
4. 动态过渡效果(根据导航方向)
<template>
<router-view v-slot="{ Component }">
<transition
:name="transitionName"
mode="out-in"
>
<component :is="Component" :key="$route.path" />
</transition>
</router-view>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const transitionName = ref('slide-right')
// 监听路由变化,根据导航深度决定动画方向
watch(
() => router.currentRoute.value,
(to, from) => {
// 获取路由深度
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
// 根据深度变化决定动画方向
transitionName.value = toDepth < fromDepth ? 'slide-right' : 'slide-left'
}
)
</script>
<style>
/* 向右滑动 */
.slide-right-enter-active,
.slide-right-leave-active {
transition: all 0.5s ease;
}
.slide-right-enter-from {
transform: translateX(-100%);
}
.slide-right-leave-to {
transform: translateX(100%);
}
/* 向左滑动 */
.slide-left-enter-active,
.slide-left-leave-active {
transition: all 0.5s ease;
}
.slide-left-enter-from {
transform: translateX(100%);
}
.slide-left-leave-to {
transform: translateX(-100%);
}
</style>
5. 实际应用场景
<!-- 移动端页面切换效果 -->
<template>
<router-view v-slot="{ Component, route }">
<!--
移动端常见的页面切换效果:
1. 前进:从右向左滑入
2. 后退:从左向右滑入
3. 层级切换:缩放效果
-->
<transition
:name="getTransitionName(route)"
mode="out-in"
@before-enter="onBeforeEnter"
@enter="onEnter"
@leave="onLeave"
>
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const routeHistory = ref([]) // 记录路由历史
// 根据路由历史判断是前进还是后退
const getTransitionName = (route) => {
const currentIndex = routeHistory.value.indexOf(route.path)
const lastRoute = routeHistory.value[routeHistory.value.length - 1]
// 更新路由历史
routeHistory.value.push(route.path)
// 判断导航方向
if (currentIndex === -1) {
// 新路由:前进
return 'slide-left'
} else if (currentIndex < routeHistory.value.indexOf(lastRoute)) {
// 后退
return 'slide-right'
} else {
// 层级切换
return 'scale'
}
}
// 动画钩子
const onBeforeEnter = (el) => {
// 可以在这里添加初始样式
el.style.opacity = 0
}
const onEnter = (el, done) => {
// 可以使用 GSAP 等动画库
gsap.to(el, {
opacity: 1,
duration: 0.5,
onComplete: done
})
}
const onLeave = (el, done) => {
gsap.to(el, {
opacity: 0,
duration: 0.5,
onComplete: done
})
}
</script>
6. 使用建议
1.选择合适的过渡模式
// 1. out-in:适合大多数场景,避免内容重叠
mode: 'out-in'
// 2. in-out:特殊效果,新内容从旧内容上方滑入
mode: 'in-out'
// 3. 默认:同时进行,可能造成内容重叠
mode: undefined
2.控制过渡时间
/* 不要设置太长的过渡时间,影响用户体验 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease; /* 建议 300-500ms */
}
3.处理过渡过程中的交互
// 禁用过渡期间的点击事件
const isTransitioning = ref(false)
const onBeforeEnter = () => {
isTransitioning.value = true
}
const onAfterEnter = () => {
isTransitioning.value = false
}
这些示例涵盖了 Vue3 路由动画的主要使用场景:
- 基础页面切换动画
- 方向感知的动画
- 移动端常见过渡效果
- 自定义动画效果
记住要注意:
- 动画时长要适中
- 选择合适的过渡模式
- 考虑性能影响
- 移动端和桌面端可能需要不同的动画效果