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

未用react-router-dom,单页网站如何获取哈希路由并更新导航激活状态?

不需要使用react-router-dom,两种原生实现方案如下

方案一:监听浏览器哈希变化(适合直接通过a标签哈希跳转的场景)

利用浏览器原生的hashchange事件,监听地址栏哈希值的变化,同步更新导航激活状态,同时初始化时读取当前哈希值避免页面刷新后状态不一致。

import { useState, useEffect } from 'react';
import { AiOutlineHome, AiOutlineUser } from 'react-icons/ai';

const Nav = ({ isToggled, onToggle }) => {
  // 初始化时读取当前地址栏哈希,默认值为#
  const [activeNav, setActiveNav] = useState(window.location.hash || '#');

  useEffect(() => {
    const handleHashChange = () => {
      const currentHash = window.location.hash || '#';
      setActiveNav(currentHash);
    };

    // 挂载时绑定哈希变化监听
    window.addEventListener('hashchange', handleHashChange);
    // 卸载时移除监听,避免内存泄漏
    return () => window.removeEventListener('hashchange', handleHashChange);
  }, []);

  return (
    <nav>
      <a
        href='#'
        onClick={() => setActiveNav('#')} // 点击时即时更新状态,提升交互流畅度
        className={activeNav === '#' ? 'active' : ''}
      >
        <AiOutlineHome />
      </a>
      <a
        href='#about'
        onClick={() => setActiveNav('#about')}
        className={activeNav === '#about' ? 'active' : ''}
      >
        <AiOutlineUser />
      </a>
      {/* 其他导航项 */}
    </nav>
  );
};

方案二:监听滚动事件(适合平滑滚动到锚点的场景)

如果你的页面是通过滚动定位到对应区块(而非直接修改哈希),可以监听滚动事件,判断当前视口内的目标区块,同步更新导航激活状态。

import { useState, useEffect } from 'react';
import { AiOutlineHome, AiOutlineUser } from 'react-icons/ai';

const Nav = ({ isToggled, onToggle }) => {
  const [activeNav, setActiveNav] = useState('#');

  useEffect(() => {
    // 节流函数,优化滚动事件触发频率
    const throttle = (func, delay) => {
      let timer = null;
      return () => {
        if (!timer) {
          timer = setTimeout(() => {
            func();
            timer = null;
          }, delay);
        }
      };
    };

    const handleScroll = () => {
      const sections = document.querySelectorAll('section[id]');
      let currentHash = '#';

      sections.forEach(section => {
        const sectionTop = section.offsetTop;
        const sectionHeight = section.offsetHeight;
        // 100是偏移量,可根据导航栏高度调整
        if (window.scrollY >= sectionTop - 100 && window.scrollY < sectionTop + sectionHeight - 100) {
          currentHash = `#${section.id}`;
        }
      });

      if (currentHash !== activeNav) {
        setActiveNav(currentHash);
        // 可选:同步更新地址栏哈希
        window.history.pushState(null, null, currentHash);
      }
    };

    const throttledScroll = throttle(handleScroll, 100);
    window.addEventListener('scroll', throttledScroll);
    // 初始化时执行一次,设置初始状态
    handleScroll();
    return () => window.removeEventListener('scroll', throttledScroll);
  }, [activeNav]);

  return (
    <nav>
      <a
        href='#'
        onClick={(e) => {
          e.preventDefault();
          window.scrollTo({ top: 0, behavior: 'smooth' });
          setActiveNav('#');
        }}
        className={activeNav === '#' ? 'active' : ''}
      >
        <AiOutlineHome />
      </a>
      <a
        href='#about'
        onClick={(e) => {
          e.preventDefault();
          document.getElementById('about').scrollIntoView({ behavior: 'smooth' });
          setActiveNav('#about');
        }}
        className={activeNav === '#about' ? 'active' : ''}
      >
        <AiOutlineUser />
      </a>
      {/* 其他导航项 */}
    </nav>
  );
};

方案选择建议

  • 若只是单纯通过a标签哈希跳转,方案一足够简洁高效;
  • 若使用平滑滚动到锚点的交互逻辑,方案二能更精准地匹配当前视口位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 13:48:23