单页面应用路由切换动画

单页应用没有浏览器自带的整页刷新动画,路由切换像「瞬间切图」,用户体验生硬。本文演示如何借助 Vue Router 的导航守卫 + Vue 的 <transition> 系统,实现方向感滑动动画(前进右滑,后退左滑),并保持嵌套路由、异步组件、keep-alive 等特性零侵入。

一、设计思路:把「方向」抽象成状态

核心只有两步:

  1. 在路由元信息 meta.index 中定义层级;
  2. 在全局 beforeEach 钩子内比较「到」与「从」的层级,得出 direction: 'right' | 'left'
js 复制代码
// router/index.js
router.beforeEach((to, from, next) => {
  const fromIndex = from.matched[0]?.meta.index ?? -1;
  const toIndex   = to.matched[0]?.meta.index   ?? -1;
  store.routerDirection.direction = toIndex >= fromIndex ? 'right' : 'left';
  next();
});

store.routerDirection 是一个极轻量的共享状态,仅存放当前方向,确保任何组件都可读取而不耦合。

二、全局布局:只让主内容区域参与动画

vue 复制代码
<!-- App.vue -->
<template>
  <div>
    <!-- 固定导航 -->
    <nav class="fixed top-0 w-full h-10 bg-gray-900 text-white flex-center">
      <router-link to="/" exact active-class="text-yellow-400">Home</router-link>
      <router-link to="/about" active-class="text-yellow-400">About</router-link>
      <router-link to="/user" active-class="text-yellow-400">User</router-link>
    </nav>

    <!-- 占位条,避免内容被固定导航遮挡 -->
    <div class="h-10" />

    <!-- 主视口:动画只发生在这里 -->
    <main class="min-h-screen py-10 lg:w-1/2 mx-auto">
      <transition :name="direction">
        <router-view />
      </transition>
    </main>

    <!-- 页脚不参与动画,保持静止 -->
    <footer class="border-t bg-gray-100 text-center py-10">Footer</footer>
  </div>
</template>

关键点:

  • <transition> 包裹 <router-view>,而非整个页面,避免页脚抖动。
  • :name="direction" 根据状态动态切换 rightleft 动画类名。

三、CSS:利用绝对定位实现「滑出 / 滑入」

css 复制代码
.right-leave-active,
.left-leave-active {
  position: absolute;
  width: 100%;
  transition: 0.5s;
}

.right-leave-active {
  transform: translateX(-50%);
  opacity: 0;
}
.right-enter {
  transform: translateX(50%);
  opacity: 0;
}
.right-enter-active {
  transition: 0.5s;
}

/* 方向相反,数值对称 */
.left-leave-active {
  transform: translateX(50%);
  opacity: 0;
}
.left-enter {
  transform: translateX(-50%);
  opacity: 0;
}
.left-enter-active {
  transition: 0.5s;
}
  • 绝对定位 让新旧两页同层重叠,避免布局抖动;
  • translateX ±50% 创造视差,视觉上更像原生应用;
  • opacity 同步淡出淡入,掩盖异步组件加载时的空档。

四、嵌套路由与 keep-alive 的无缝协作

示例中 /user 使用嵌套路由:

js 复制代码
{
  path: '/user',
  component: () => import('@/views/user/Layout.vue'),
  meta: { index: 2 },
  children: [
    { path: '', component: () => import('@/views/user/Profile.vue') },
    { path: 'address', component: () => import('@/views/user/Address.vue') }
  ]
}
  • Layout 外壳不参与动画;子路由切换时 <router-view> 嵌套深度不变,动画依旧生效。
  • keep-alive 包裹子路由组件后,切换动画不会触发重新创建,滚动位置与表单状态均可保留。

五、可扩展方向

  • 手势返回:监听 touchstart/touchend,计算滑动方向并手动调用 router.back()
  • 多层级深度:给子路由再定义 meta.index,动画可递归判断;
  • 微动画库:集成 @vueuse/motionframer-motion 做更细腻的共享元素过渡。
相关推荐
萧行之1 小时前
可视化技术复盘:从图形语法看 D3、Vega-Lite、ECharts、Observable Plot
前端·学习·数据可视化
尾善爱看海9 小时前
Vue 面试收官篇:SSR、性能优化落地、30 道高频面试题精讲(附标准答案)
前端·javascript·vue.js·面试·vue
weixin_BYSJ19879 小时前
【计算机毕设】基于SpringBoot与Vue的文物保护档案管理系统08621
vue.js·spring boot·spring cloud·微服务·架构·django·课程设计
Bs_MoneyMagnet10 小时前
基于springboot+vue的个人健康管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·vue3·springboot3·计算机毕业设计
驳是10 小时前
一个组件,提升 react-router 开发的幸福感
前端·preact
GreenTea10 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
星云API技术支持10 小时前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信
京东云开发者10 小时前
81.8 秒的视频,我们改了 15 个版本:一次纯 Codex 驱动的 AI-native 视频实践
前端·aigc
Csvn11 小时前
TypeScript 大型项目架构:从单体 tsconfig 到分层可扩展的工程
前端
Bs_MoneyMagnet12 小时前
基于springboot+vue的心理咨询预约与随访平台的设计与实现 源码+文档
vue.js·spring boot·后端·spring·毕业设计·旅游·计算机毕业设计