React路由切换时如何实现滚动过渡效果?求方案及示例
React路由切换时实现滚动过渡的几种方法
作为经常折腾React路由过渡的开发者,我完全懂你想要的那种丝滑跳转体验!除了简单调用scrollUp/scrollDown,还有不少更优雅的实现方式,下面结合你的现有代码给你几个实用示例:
方法1:监听路由变化 + 原生平滑滚动(基础无依赖版)
你可以做一个全局的滚动控制组件,监听路由切换事件,用浏览器原生的平滑滚动API实现过渡,不需要额外装包:
首先把你的路由用Switch包裹(假设你用的是react-router-dom v5,v6的话语法稍作调整即可),然后添加这个ScrollToTop组件:
import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; // 全局滚动控制组件 function ScrollToTop() { const { pathname } = useLocation(); useEffect(() => { // 平滑滚动到顶部,也可以改成滚动到指定元素位置 window.scrollTo({ top: 0, behavior: 'smooth' // 这个属性是实现平滑过渡的关键 }); }, [pathname]); // 路由路径变化时触发 return null; // 这个组件不需要渲染DOM } // 改造你的路由结构 function App() { return ( <div className="content"> <ScrollToTop /> {/* 放在路由外层,全局生效 */} <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/products" component={Products} /> <Route path="/partners" component={Partners} /> </div> ); }
如果想要自定义滚动速度或者曲线,可以用requestAnimationFrame手写动画逻辑:
function smoothScrollToTop() { const currentScroll = window.pageYOffset; if (currentScroll > 0) { window.requestAnimationFrame(smoothScrollToTop); // 每次滚动当前距离的1/8,数值越小滚动越慢 window.scrollTo(0, currentScroll - currentScroll / 8); } } // 替换useEffect里的window.scrollTo为这个函数 useEffect(() => { smoothScrollToTop(); }, [pathname]);
方法2:结合react-transition-group实现页面过渡+滚动联动
如果想要同时实现页面淡入淡出和滚动过渡的同步效果,react-transition-group是个很合适的工具,步骤如下:
- 先安装依赖:
npm install react-transition-group
- 改造路由结构,用过渡组件包裹路由:
import { Switch, Route, useLocation } from 'react-router-dom'; import { CSSTransition, TransitionGroup } from 'react-transition-group'; function App() { const location = useLocation(); return ( <div className="content"> <TransitionGroup> <CSSTransition key={location.key} // 用路由key区分不同页面 timeout={500} // 过渡时长,和CSS对应 classNames="page-transition" onEnter={() => window.scrollTo(0, 0)} // 进入新页面时滚动到顶 onExited={() => window.scrollTo(0, 0)} // 旧页面退出后确保位置正确 > <Switch location={location}> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/products" component={Products} /> <Route path="/partners" component={Partners} /> </Switch> </CSSTransition> </TransitionGroup> </div> ); }
然后添加对应的CSS过渡样式:
/* 页面进入时的初始状态 */ .page-transition-enter { opacity: 0; transform: translateY(20px); } /* 页面进入的过渡动画 */ .page-transition-enter-active { opacity: 1; transform: translateY(0); transition: opacity 500ms, transform 500ms; } /* 页面退出的初始状态 */ .page-transition-exit { opacity: 1; } /* 页面退出的过渡动画 */ .page-transition-exit-active { opacity: 0; transition: opacity 500ms; }
这种方式能让页面切换动画和滚动过渡完美同步,体验更连贯。
方法3:自定义局部滚动容器(适合固定侧边栏场景)
如果你的页面是局部滚动(比如侧边栏固定,只有内容区滚动),可以给内容容器加ref,控制容器的滚动位置而非整个window:
import { useEffect, useRef } from 'react'; import { useLocation } from 'react-router-dom'; function App() { const contentRef = useRef(null); const { pathname } = useLocation(); useEffect(() => { if (contentRef.current) { contentRef.current.scrollTo({ top: 0, behavior: 'smooth' }); } }, [pathname]); return ( <div className="content" ref={contentRef} style={{ overflowY: 'auto', height: '100vh' }} // 设置容器可滚动 > <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/products" component={Products} /> <Route path="/partners" component={Partners} /> </div> ); }
新手友好提示
- 如果你用的是
react-router-dom v6,只需要把Switch换成Routes,component={Home}改成element={<Home />}即可,滚动逻辑完全通用。 - 原生平滑滚动的
behavior: 'smooth'大部分现代浏览器都支持,如果要兼容旧浏览器,可以安装smoothscroll-polyfill库做兼容。
内容的提问来源于stack exchange,提问作者max
相关产品推荐
相关产品推荐

