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

React多页面导航锚点跳转失效:跨路由滚动解决方案

跨页面锚点跳转失效修复 + 原生替代方案

先解决react-scroll的跨页面锚点问题

react-scroll默认只处理同页面内的滚动,跨页面时得先跳转到目标路由,再在目标页面触发滚动定位。

实现步骤:

  • 点击导航链接时,先判断当前页面是否为目标页面:
    • 是则直接调用scroller.scrollTo完成同页面滚动
    • 否则用React Router的useNavigate跳转到目标页面,同时在URL中携带锚点参数(比如/#realtime)
  • 在目标页面的useEffect中监听URL的hash变化,触发react-scroll的滚动逻辑

代码示例:

通用导航组件

import { useNavigate, useLocation } from 'react-router-dom';
import { scroller } from 'react-scroll';

const NavLink = ({ targetId, targetPath, label }) => {
  const navigate = useNavigate();
  const location = useLocation();

  const handleClick = () => {
    if (location.pathname === targetPath) {
      // 同页面直接滚动
      scroller.scrollTo(targetId, {
        duration: 800,
        delay: 0,
        smooth: 'easeInOutQuart'
      });
    } else {
      // 跨页面跳转并携带锚点
      navigate(`${targetPath}/#${targetId}`);
    }
  };

  return <button onClick={handleClick}>{label}</button>;
};

// 使用示例:
// <NavLink targetId="realtime" targetPath="/" label="RealTime" />
// <NavLink targetId="moodboards" targetPath="/concepts" label="Moodboards" />

目标页面(以Home页为例)

import { useEffect } from 'react';
import { scroller } from 'react-scroll';
import { useLocation } from 'react-router-dom';

const Home = () => {
  const location = useLocation();

  useEffect(() => {
    const hash = location.hash.slice(1); // 去掉#号
    if (hash === 'realtime') {
      scroller.scrollTo(hash, {
        duration: 800,
        delay: 0,
        smooth: 'easeInOutQuart'
      });
    }
  }, [location.hash]);

  return (
    <div>
      <div id="videoGallery">VideoGallery</div>
      <div id="realtime">RealTime</div>
    </div>
  );
};

Concepts页同理,只需监听hash是否为moodboards即可。


无需react-scroll的原生实现方案

直接用浏览器原生API结合React Router就能搞定,不用依赖第三方库:

实现步骤:

  1. 给每个需要跳转的区域添加唯一id(比如<div id="realtime">...</div>)
  2. 导航链接用React Router的Link组件,直接指向带hash的路由路径
  3. 在目标页面监听路由变化,手动触发滚动到对应锚点(解决单页面应用中hash不触发原生滚动的问题)

代码示例:

导航组件

import { Link } from 'react-router-dom';

const Nav = () => {
  return (
    <nav>
      <Link to="/#realtime">RealTime</Link>
      <Link to="/concepts/#moodboards">Moodboards</Link>
    </nav>
  );
};

通用滚动Hook(可复用)

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

const useScrollToAnchor = () => {
  const location = useLocation();

  useEffect(() => {
    const hash = location.hash;
    if (hash) {
      const targetElement = document.querySelector(hash);
      if (targetElement) {
        // 原生平滑滚动
        targetElement.scrollIntoView({
          behavior: 'smooth',
          block: 'start'
        });
      }
    }
  }, [location]);
};

// 在Home和Concepts页面中使用:
const Home = () => {
  useScrollToAnchor();

  return (
    <div>
      <div id="videoGallery">VideoGallery</div>
      <div id="realtime">RealTime</div>
    </div>
  );
};

const Concepts = () => {
  useScrollToAnchor();

  return (
    <div>
      <div id="imageGallery">ImageGallery</div>
      <div id="moodboards">Moodboards</div>
    </div>
  );
};

进阶自定义滚动动画

如果需要更精细的动画控制(比如自定义缓动曲线),可以手动实现滚动逻辑:

const smoothScrollTo = (targetElement, duration = 800) => {
  const startPosition = window.pageYOffset;
  const targetPosition = targetElement.getBoundingClientRect().top + startPosition;
  const distance = targetPosition - startPosition;
  let startTime = null;

  const animation = (currentTime) => {
    if (startTime === null) startTime = currentTime;
    const timeElapsed = currentTime - startTime;
    const progress = Math.min(timeElapsed / duration, 1);
    // 自定义easeInOutQuart缓动函数
    const ease = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;
    window.scrollTo(0, startPosition + distance * ease);
    if (timeElapsed < duration) requestAnimationFrame(animation);
  };

  requestAnimationFrame(animation);
};

// 在useScrollToAnchor中替换scrollIntoView:
// smoothScrollTo(targetElement);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 02:06:04