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

React项目中Scroll to Top按钮不显示问题求助(react-router-dom v6)

React Router v6 下回到顶部按钮不触发滚动事件的解决方案

在 React 18 + React Router v6.3.0 项目中,回到顶部按钮在页面滚动超过300px时不显示,滚动事件未触发;手动设置isVisible为true时按钮显示,但点击无效果。相同代码在无React Router的项目中可正常运行。

问题根源

核心原因是滚动容器不是window——如果你的路由组件(比如Home)或其外层容器设置了height: 100vh+overflow: auto/scroll这类样式,页面的滚动实际发生在该容器内,而非window对象。此时监听window的滚动事件自然不会触发,调用window.scrollTo也无法生效。

解决方案

方案一:让window成为滚动容器

检查页面布局,移除路由组件或外层容器中类似以下的样式:

.container {
  height: 100vh;
  overflow: auto;
}

让body/window承担滚动容器的角色,原代码即可正常工作。

方案二:监听正确的滚动容器(适配局部滚动场景)

如果必须保留局部滚动,修改ScrollToTop组件,针对目标容器监听滚动事件并执行滚动操作:

修改后的ScrollToTop组件

import { useEffect, useState, useRef } from "react";
import { BiArrowFromBottom } from "react-icons/bi";
import "./scrollToTop.scss";

// 可传入滚动容器的ref,默认使用document.body
const ScrollToTop = ({ scrollContainerRef = null }) => {
  const [isVisible, setIsVisible] = useState(false);
  const defaultContainerRef = useRef(document.body);
  const targetContainer = scrollContainerRef?.current || defaultContainerRef.current;

  const toggleVisibility = () => {
    if (targetContainer.scrollTop > 300) {
      setIsVisible(true);
    } else {
      setIsVisible(false);
    }
  };

  const scrollToTop = () => {
    targetContainer.scrollTo({
      top: 0,
      behavior: "smooth",
    });
  };

  useEffect(() => {
    targetContainer.addEventListener("scroll", toggleVisibility);
    return () => targetContainer.removeEventListener("scroll", toggleVisibility);
  }, [targetContainer]);

  return (
    <div className="top-to-btm">
      {isVisible && (
        <BiArrowFromBottom
          onClick={scrollToTop}
          className="icon-position icon-style"
        />
      )}
    </div>
  );
};

export default ScrollToTop;

组件使用示例(以Home局部滚动为例)

// Home.jsx
import { useRef } from "react";
import ScrollToTop from "./components/backtotop/scrollToTop";

const Home = () => {
  const scrollContainerRef = useRef(null);

  return (
    <div 
      ref={scrollContainerRef}
      style={{ height: "100vh", overflow: "auto" }}
    >
      {/* 页面内容 */}
      <ScrollToTop scrollContainerRef={scrollContainerRef} />
    </div>
  );
};

额外调试技巧

  • 在toggleVisibility函数中添加console.log(targetContainer.scrollTop),确认是否能获取到正确的滚动距离。
  • 如果仍使用window滚动,可统一用window.pageYOffset判断滚动位置(兼容不同浏览器对document.body.scrollTop/document.documentElement.scrollTop的差异)。

原问题代码

ScrollToTop 组件

import { useEffect, useState } from "react";
import { BiArrowFromBottom } from "react-icons/bi";
import "./scrollToTop.scss";

const ScrollToTop = () => {
  const [isVisible, setIsVisible] = useState(false);

  const toggleVisibility = () => {
    if (window.pageYOffset > 300) {
      setIsVisible(true);
    } else {
      setIsVisible(false);
    }
  };

  const scrollToTop = () => {
    window.scrollTo({
      top: 0,
      behavior: "smooth",
    });
  };

  useEffect(() => {
    window.addEventListener("scroll", toggleVisibility);

    return () => {
      window.removeEventListener("scroll", toggleVisibility);
    };

  }, []);

  return (
      <div className="top-to-btm">
        {isVisible && (
          <BiArrowFromBottom
            onClick={scrollToTop}
            className="icon-position icon-style"
          />
        )}
      </div>
  );
};

export default ScrollToTop;

App 组件

import ScrollToTop from "./components/backtotop/scrollToTop";
import { BrowserRouter } from "react-router-dom";

const App = () => {
  return (
    <BrowserRouter>
        <Routes>
          <Route path="/" element={<Home />} />
        </Routes>
        <ScrollToTop />
    </BrowserRouter>
  );
};

export default App;

SCSS 样式

.top-to-btm {
    position: relative;
  }
  .icon-position{
    position: fixed;
    bottom: 40px;
    right: 35px;
    z-index: 20;
  }
  .icon-style{
    background-color: #725034;
    border: 2px solid #fff;
    border-radius: 50%;
    height: 50px;
    width: 50px;
    color: #fff;
    cursor: pointer;
    animation: movebtn 3s ease-in-out infinite;
    transition: all .5s ease-in-out;
  }
  .icon-style:hover{
    animation: none;
    background: #fff;
    color: #725034;
    border: 2px solid  #725034;
  }
  @keyframes movebtn {
    0%{
      transform: translateY(0px);
    }
    25%{
      transform: translateY(20px);
    }
    50%{
      transform: translateY(0px);
    }
    75%{
      transform: translateY(-20px);
    }
    100%{
      transform: translateY(0px);
    }
  }

内容的提问来源于stack exchange,提问作者r2d2

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 12:55:25