使用Router加载framer-motion页面时的动画异常问题
问题描述
场景
- 基于Vite搭建React项目,使用framer-motion实现页面元素动画
- 在
src/components/FramerMotion目录下创建Motion.jsx组件,通过react-router-dom配置多页面路由,使用useNavigate()实现页面跳转
预期效果
- 从首页(Hello.jsx)导航至Motion页面时,所有
<motion.div>元素按配置的variants规则,以0.25秒的延迟依次加载动画 - 刷新Motion页面时,所有元素同样按上述延迟规则重新触发加载动画
实际异常
- 路由跳转时动画表现正常
- 刷新Motion页面时,前两个
<motion.div>直接显示无延迟,其余元素可正常按延迟加载
相关代码
Motion.jsx
import { motion, } from "framer-motion" const gridContainerVariants = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.25, }, }, } const gridSquareVariants = { hidden: { opacity: 0 }, show: { opacity: 1 }, } const Motion = () => { return ( <div className="flex flex-col gap-10 overflow-x-hidden"> <motion.div variants={gridContainerVariants} initial="hidden" animate="show" className="grid grid-cols-3 p-10 gap-10" > {/* Fade Up */} <motion.div variants={gridSquareVariants} className="bg-slate-800 aspect-square rounded-lg justify-center flex items-center gap-10" > </motion.div> {/* Shape Shifting */} <motion.div variants={gridSquareVariants} className="bg-slate-800 aspect-square rounded-lg justify-center flex items-center gap-10" > </motion.div> {/* Button */} <motion.div variants={gridSquareVariants} className="bg-slate-800 aspect-square rounded-lg justify-center flex items-center gap-10" > </motion.div> {/* Drag */} <motion.div variants={gridSquareVariants} className="bg-slate-800 aspect-square rounded-lg justify-center flex items-center gap-10" > </motion.div> {/* Scroll Progress */} <motion.div variants={gridSquareVariants} className="bg-slate-800 aspect-square rounded-lg justify-center flex items-center gap-10" > </motion.div> {/* SVG Animation */} <motion.div variants={gridSquareVariants} className="bg-slate-800 aspect-square rounded-lg justify-center flex items-center gap-10" > </motion.div> </motion.div> </div> ) } export default Motion
App.jsx
import Motion from "./components/FramerMotion/Motion"; import Hello from "./components/HelloTest/Hello"; import Auction from "./components/HOC/Auction"; import MovingBorder from "./components/Tailwind/MovingBorder"; import ResponsiveNavigation1 from "./components/Tailwind/ResponsiveNavigation1"; import ResponsiveNavigation2 from "./components/Tailwind/ResponsiveNavigation2"; import { BrowserRouter, Routes, Route } from "react-router-dom"; function App() { return ( <> <BrowserRouter> <Routes> <Route path="/" element={<Hello />} /> <Route path="/auction" element={<Auction />} /> <Route path="/movingborder" element={<MovingBorder />} /> <Route path="/responsivenavigation1" element={<ResponsiveNavigation1 />}/> <Route path="/responsivenavigation2" element={<ResponsiveNavigation2 />}/> <Route path="/motion" element={<Motion />} /> </Routes> </BrowserRouter> </> ); } export default App;
项目目录结构
/public/ └─ vite.svg /src/ /components/ /FramerMotion/ └─ Motion.jsx /HelloTest/ └─ Hello.jsx /HOC/ ├─ Auction.jsx ├─ HOC.jsx ├─ Person1.jsx └─ Person2.jsx /Tailwind/ ├─ MovingBorder.jsx ├─ ResponsiveNavigation1.jsx └─ ResponsiveNavigation2.jsx ├─ App.jsx ├─ index.css └─ main.jsx /.gitignore /eslint.config.js /index.html /package.json /postcss.config.js /README.md /tailwind.config.js /vite.config.js
解决方案
原因分析
刷新页面时浏览器会优先渲染可视区域内的元素,导致framer-motion父容器的staggerChildren延迟规则未及时作用于前两个子元素,子元素的hidden初始状态被跳过。
可行修复方案
方案1:给父容器动画添加极小延迟
修改父容器的过渡配置,确保所有子元素的初始状态生效后再启动动画:
const gridContainerVariants = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.25, delay: 0.05 // 添加极小延迟,避免初始渲染冲突 }, }, }
方案2:给子元素显式声明初始状态
虽然父容器的variants会传递给子元素,但刷新时可能存在状态传递延迟,给每个子元素显式设置initial="hidden":
<motion.div variants={gridSquareVariants} initial="hidden" className="bg-slate-800 aspect-square rounded-lg justify-center flex items-center gap-10" > </motion.div>
方案3:用AnimatePresence包裹父容器
针对路由场景,AnimatePresence可以更精准地控制页面挂载时的动画触发逻辑:
import { motion, AnimatePresence } from "framer-motion" const Motion = () => { return ( <div className="flex flex-col gap-10 overflow-x-hidden"> <AnimatePresence mode="wait"> <motion.div key="motion-grid" variants={gridContainerVariants} initial="hidden" animate="show" exit="hidden" className="grid grid-cols-3 p-10 gap-10" > {/* 子元素保持不变 */} </motion.div> </AnimatePresence> </div> ) }
mode="wait"会确保初始动画完成后再处理其他状态,避免刷新时的渲染优先级冲突。
内容的提问来源于stack exchange,提问作者A AMRITH GOLD
相关产品推荐
相关产品推荐

