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

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是个很合适的工具,步骤如下:

  1. 先安装依赖:
npm install react-transition-group
  1. 改造路由结构,用过渡组件包裹路由:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:35:33