如何用React Router 6实现双路由同时显示的页面过渡动画?
React Router 6 + Frame Motion 实现双路由并行过渡动画
完全可以实现你想要的效果——React Router 6 结合 Frame Motion 是实现这类双路由同时显示过渡的最优方案,比你之前尝试的 setTimeout 或原生 View Transitions API 更可控、更流畅。
核心实现思路
- 用布局路由包裹过渡逻辑:借助 React Router 6 的
<Outlet>组件,把过渡动画的控制放在父布局组件中,这样能同时追踪新旧路由组件的挂载/卸载状态。 - Frame Motion 的 AnimatePresence 关键作用:这个组件专门处理组件卸载时的动画,能让旧页面的退出动画和新页面的进入动画并行执行,完美实现两个路由同时显示的过渡效果,不需要手动用 setTimeout 同步时机。
具体代码示例
先安装依赖:
npm install react-router-dom@6 framer-motion
父布局组件(处理过渡)
import { Outlet, useLocation } from 'react-router-dom'; import { AnimatePresence, motion } from 'framer-motion'; export default function AppLayout() { const location = useLocation(); return ( <div style={{ position: 'relative', minHeight: '100vh', overflow: 'hidden' }}> <AnimatePresence mode="wait"> <motion.div key={location.pathname} initial={{ scale: 0.8, opacity: 0, borderRadius: '16px' }} animate={{ scale: 1, opacity: 1, borderRadius: 0 }} exit={{ scale: 0.8, opacity: 0, borderRadius: '16px' }} transition={{ duration: 0.5, ease: 'easeInOut' }} style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} > <Outlet /> </motion.div> </AnimatePresence> </div> ); }
路由配置
import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import AppLayout from './AppLayout'; import Home from './pages/Home'; import Work from './pages/Work'; const router = createBrowserRouter([ { element: <AppLayout />, children: [ { path: '/', element: <Home /> }, { path: '/work', element: <Work /> }, ], }, ]); export default function App() { return <RouterProvider router={router} />; }
为什么你之前的方案不流畅?
- setTimeout 方式本质是强行同步路由跳转和动画,容易出现时序偏差,导致动画和路由切换脱节,出现卡顿或跳帧。
- View Transitions API 本身支持跨路由过渡,但需要精准控制路由切换和 API 触发的时机,对 React 组件的生命周期配合要求较高,不如 Frame Motion 封装的方案直接。
贴近 pizzapizza 效果的调整
如果要复刻目标页面的具体动画细节,可以修改 motion 组件的 exit 和 initial 属性:
- 比如旧页面退出时不仅缩小,还可以添加位移(
x/y属性)、模糊效果(filter: blur(8px)) - 新页面进入时可以先保持全屏覆盖,再缩小到正常尺寸,配合背景色过渡
内容的提问来源于stack exchange,提问作者shplvk
相关产品推荐
相关产品推荐

