如何在ReactJS中结合React-Router-DOM维护URL导航与单页滚动链接
问题描述
- 基于ReactJS + React-Router-DOM开发项目,导航栏包含
home、about、services、portfolio、contact五个链接 home和about为单页滚动锚点链接,services/portfolio/contact对应独立路由页面- 使用
<a>标签实现锚点跳转而非React-Router的Link组件,因Link对锚点的表现不符合预期 - 正常场景:从
home跳转到about时,URL从domain变为domain/#about;从domain/#about跳转到services时,URL变为domain/services - 异常场景:处于
services/portfolio/contact页面时,点击home或about链接,URL会变为domain/services#about,而非预期的domain/#about
import React, { useEffect } from "react"; import { Link, useLocation } from "react-router-dom"; import "./css/navbar.css"; import Logo from "./Logo"; function Navbar(props) { const location = useLocation(); useEffect(() => { console.log(location); }, [location]); const singlePageScrollLinks = () => { return ( <> <li className="nav-item"> <a href="#home" className={`nav-link ${ location.pathname === "/" && location.hash === "#home" ? "active" : "" }`} > Home </a> </li> <li className="nav-item"> <a href="#about" className={`nav-link ${ location.pathname === "/" && location.hash === "#about" ? "active" : "" }`} > About </a> </li> </> ); }; return ( <div style={{ position: "sticky", top: "-2px", backgroundColor: "#2c2c2c", zIndex: "2", }} id="nav-page" > <div className="d-flex justify-content-between list-unstyled top-nav"> <li>+91 9876543210</li> <li>qwerty@mail.com</li> </div> <nav className="navbar navbar-expand-lg bg-body-tertiary custom-nav" style={{ borderRadius: "45px 0 0 0" }} > <div className="container-fluid"> <Link className="navbar-brand" to="/" style={{ width: "1px" }}> <Logo /> </Link> <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" > <span className="navbar-toggler-icon"></span> </button> <div className="collapse navbar-collapse" id="navbarSupportedContent"> <ul className="navbar-nav ms-auto mb-2 mb-lg-0"> {singlePageScrollLinks()} <li className="nav-item"> <Link className="nav-link" to="/services"> Services </Link> </li> <li className="nav-item"> <Link className="nav-link" to="/portfolio"> Portfolio </Link> </li> <li className="nav-item"> <Link className="nav-link" to="/contact"> Contact </Link> </li> </ul> </div> </div> </nav> </div> ); } export default Navbar;
解决方案
问题根源:相对路径的锚点href="#about"会在当前路由路径后追加哈希值,而非回到根路径。以下两种方式可修复:
方式1:使用绝对路径锚点
直接将<a>标签的href改为绝对路径,确保无论当前在哪个路由页面,点击都会跳转到根路径下的对应锚点:
// 修改singlePageScrollLinks里的a标签 <li className="nav-item"> <a href="/#home" className={`nav-link ${ location.pathname === "/" && location.hash === "#home" ? "active" : "" }`} > Home </a> </li> <li className="nav-item"> <a href="/#about" className={`nav-link ${ location.pathname === "/" && location.hash === "#about" ? "active" : "" }`} > About </a> </li>
方式2:结合React-Router编程式导航(推荐)
若希望保留单页应用无刷新特性,可通过useNavigate实现跳转,先回到根路径再滚动到锚点:
- 导入
useNavigate并初始化 - 为锚点链接添加点击事件,阻止默认跳转后手动导航到根路径+锚点
import React, { useEffect } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; // 新增useNavigate import "./css/navbar.css"; import Logo from "./Logo"; function Navbar(props) { const location = useLocation(); const navigate = useNavigate(); // 初始化navigate useEffect(() => { console.log(location); }, [location]); const handleAnchorClick = (e, anchor) => { e.preventDefault(); // 导航到根路径下的对应锚点 navigate(`/#${anchor}`); // 若自动滚动不生效,手动触发平滑滚动 setTimeout(() => { document.getElementById(anchor)?.scrollIntoView({ behavior: 'smooth' }); }, 100); }; const singlePageScrollLinks = () => { return ( <> <li className="nav-item"> <a href="#home" onClick={(e) => handleAnchorClick(e, 'home')} className={`nav-link ${ location.pathname === "/" && location.hash === "#home" ? "active" : "" }`} > Home </a> </li> <li className="nav-item"> <a href="#about" onClick={(e) => handleAnchorClick(e, 'about')} className={`nav-link ${ location.pathname === "/" && location.hash === "#about" ? "active" : "" }`} > About </a> </li> </> ); }; // 其余代码保持不变 } export default Navbar;
额外说明
两种方式下,原有的激活状态判断逻辑均无需修改,location对象会正确反映当前路径与哈希值,确保active类名正常生效。
内容的提问来源于stack exchange,提问作者Abhishek Surela
相关产品推荐
相关产品推荐

