You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Framer Motion页面跳转时滚动置顶干扰退出动画问题

解决React Router V6 + Framer Motion 退出动画前页面自动滚顶的问题

问题根源

React Router V6默认在导航时会自动滚动到页面顶部,这个行为会抢先于Framer Motion的退出动画执行,导致动画在顶部位置触发,而非点击链接时的当前滚动位置。

解决方案

通过禁用React Router自动滚动行为 + **手动控制导航时机(等待退出动画完成)**来解决,具体步骤如下:

  1. 配置带动画的路由结构
    用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>;
    }
    
  2. 在页面组件中控制导航与动画
    点击链接时先触发退出动画,等动画完成后再执行导航,同时禁用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;
    
  3. 新页面手动控制滚动(可选)
    如果需要新页面加载后滚动到顶部,在目标页面的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 14:21:02