React+Framer Motion页面跳转时滚动置顶干扰退出动画问题
解决React Router V6 + Framer Motion 退出动画前页面自动滚顶的问题
问题根源
React Router V6默认在导航时会自动滚动到页面顶部,这个行为会抢先于Framer Motion的退出动画执行,导致动画在顶部位置触发,而非点击链接时的当前滚动位置。
解决方案
通过禁用React Router自动滚动行为 + **手动控制导航时机(等待退出动画完成)**来解决,具体步骤如下:
配置带动画的路由结构
用AnimatePresence包裹路由,并给路由元素添加唯一key(基于当前路径),确保Framer Motion能检测路由变化触发动画:import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom'; import { AnimatePresence } from 'framer-motion'; import Page1 from './Page1'; import Page2 from './Page2'; function AnimatedRoutes() { const location = useLocation(); return ( <AnimatePresence mode="wait"> <Routes location={location} key={location.pathname}> <Route path="/" element={<Page1 />} /> <Route path="/page2" element={<Page2 />} /> </Routes> </AnimatePresence> ); } function App() { return <Router><AnimatedRoutes /></Router>; }在页面组件中控制导航与动画
点击链接时先触发退出动画,等动画完成后再执行导航,同时禁用React Router的自动滚顶:import { useState } from 'react'; import { motion } from 'framer-motion'; import { useNavigate } from 'react-router-dom'; const Page1 = () => { const [isExiting, setIsExiting] = useState(false); const navigate = useNavigate(); const handleLinkClick = () => { // 触发退出动画 setIsExiting(true); }; const onExitComplete = () => { // 动画完成后导航,禁用自动滚顶 navigate('/page2', { preventScrollReset: true }); }; return ( <motion.div initial={{ opacity: 1 }} exit={{ opacity: 0 }} animate={isExiting ? 'exit' : 'initial'} onExitComplete={onExitComplete} style={{ minHeight: '200vh', padding: '2rem' }} > <h1>页面1</h1> <p>向下滚动后点击下方链接</p> <div style={{ marginTop: '500px' }}> <button onClick={handleLinkClick}>跳转到页面2</button> </div> </motion.div> ); }; export default Page1;新页面手动控制滚动(可选)
如果需要新页面加载后滚动到顶部,在目标页面的useEffect中手动处理:import { useEffect } from 'react'; import { motion } from 'framer-motion'; const Page2 = () => { useEffect(() => { window.scrollTo(0, 0); }, []); return ( <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} style={{ minHeight: '100vh', padding: '2rem' }} > <h1>页面2</h1> </motion.div> ); }; export default Page2;
关键说明
AnimatePresence的mode="wait"属性确保退出动画完全结束后,再渲染新页面的进入动画,避免视觉冲突。navigate方法中传递{ preventScrollReset: true },彻底禁用React Router的自动滚顶行为,保证退出动画在当前滚动位置执行。
内容的提问来源于stack exchange,提问作者krishnakirit04
相关产品推荐
相关产品推荐

