React Router DOM v6.14.0路由切换时如何添加页面动画过渡?
React路由切换平滑过渡实现方法
下面是几种实用的实现方案,可根据项目需求选择:
方案一:React Transition Group + React Router(通用方案)
这是社区常用的组合,通过过渡组件管理路由切换时的动画状态。
- 安装依赖
npm install react-transition-group react-router-dom
- 配置路由与过渡组件
import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom'; import { TransitionGroup, CSSTransition } from 'react-transition-group'; import Home from './pages/Home'; import About from './pages/About'; import Contact from './pages/Contact'; function AnimatedRoutes() { const location = useLocation(); return ( <TransitionGroup> <CSSTransition key={location.key} timeout={{ enter: 300, exit: 300 }} classNames="page-transition" unmountOnExit > <Routes location={location}> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/contact" element={<Contact />} /> </Routes> </CSSTransition> </TransitionGroup> ); } function App() { return ( <Router> <AnimatedRoutes /> </Router> ); }
- 编写过渡CSS
/* 进入动画初始状态 */ .page-transition-enter { opacity: 0; transform: translateX(100%); } /* 进入动画执行状态 */ .page-transition-enter-active { opacity: 1; transform: translateX(0); transition: opacity 300ms, transform 300ms; } /* 退出动画初始状态 */ .page-transition-exit { opacity: 1; transform: translateX(0); } /* 退出动画执行状态 */ .page-transition-exit-active { opacity: 0; transform: translateX(-100%); transition: opacity 300ms, transform 300ms; }
方案二:Framer Motion(简洁高效方案)
Framer Motion封装了复杂的动画逻辑,代码更简洁,适合快速实现丰富过渡效果。
- 安装依赖
npm install framer-motion react-router-dom
- 配置路由与动画
import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom'; import { AnimatePresence, motion } from 'framer-motion'; import Home from './pages/Home'; import About from './pages/About'; import Contact from './pages/Contact'; function AnimatedRoutes() { const location = useLocation(); return ( <AnimatePresence mode="wait"> <Routes location={location} key={location.pathname}> <Route path="/" element={ <motion.div initial={{ opacity: 0, x: 100 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -100 }} transition={{ duration: 0.3 }} > <Home /> </motion.div> } /> <Route path="/about" element={ <motion.div initial={{ opacity: 0, x: 100 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -100 }} transition={{ duration: 0.3 }} > <About /> </motion.div> } /> <Route path="/contact" element={ <motion.div initial={{ opacity: 0, x: 100 }} animate={{ opacity: 1, x: 0 }} exit={{ opacity: 0, x: -100 }} transition={{ duration: 0.3 }} > <Contact /> </motion.div> } /> </Routes> </AnimatePresence> ); }
方案三:纯CSS + React Router(轻量方案)
无需额外依赖,通过路由切换时的类名变化触发CSS过渡,适合简单的淡入淡出效果。
import { BrowserRouter as Router, Routes, Route, useLocation, useEffect, useState } from 'react-router-dom'; import Home from './pages/Home'; import About from './pages/About'; import Contact from './pages/Contact'; function AnimatedRoutes() { const location = useLocation(); const [isTransitioning, setIsTransitioning] = useState(false); useEffect(() => { setIsTransitioning(true); const timer = setTimeout(() => setIsTransitioning(false), 300); return () => clearTimeout(timer); }, [location.pathname]); return ( <div className={`page-container ${isTransitioning ? 'transitioning' : ''}`}> <Routes location={location}> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/contact" element={<Contact />} /> </Routes> </div> ); }
对应的CSS:
.page-container { opacity: 1; transition: opacity 300ms ease-in-out; } .page-container.transitioning { opacity: 0; }
注意事项
- 确保路由切换时旧页面不会立即卸载(比如React Transition Group的
unmountOnExit、Framer Motion的AnimatePresence需要绑定key) - 可根据需求自定义动画类型,比如缩放、旋转等,只需修改CSS或motion组件的参数
- 嵌套路由场景下,需调整过渡组件的包裹层级,确保仅针对页面级组件触发过渡
内容的提问来源于stack exchange,提问作者Al Amin
相关产品推荐
相关产品推荐

