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

React导航栏路由下划线窗口Resize时偏移问题求解

解决React导航栏下划线窗口resize时错位的问题

方案一:纯CSS实现(推荐,简洁高效)

无需单独维护下划线组件,通过给当前激活的导航链接添加active类,用CSS伪元素实现下划线,自动适配窗口resize。

步骤1:修改导航链接的渲染

给匹配当前路由的链接添加active类:

import { useLocation } from "react-router-dom";

function Navbar() {
  const { pathname } = useLocation();
  
  return (
    <nav style={{ position: "relative", padding: "1rem 0" }}>
      <a 
        href="/home" 
        className={pathname === "/home" ? "nav-link active" : "nav-link"} 
        id="home"
      >
        首页
      </a>
      <a 
        href="/about" 
        className={pathname === "/about" ? "nav-link active" : "nav-link"}
      >
        关于
      </a>
      <a 
        href="/contact" 
        className={pathname === "/contact" ? "nav-link active" : "nav-link"}
      >
        联系我们
      </a>
    </nav>
  );
}

步骤2:添加CSS样式

用::after伪元素生成下划线,自动跟随链接的位置和宽度:

.nav-link {
  position: relative;
  margin: 0 1rem;
  text-decoration: none;
  color: #333;
}

.nav-link.active::after {
  content: "";
  position: absolute;
  bottom: -5px; /* 对应原下划线的margin-bottom */
  left: 0;
  width: 100%;
  height: 4px;
  background: linear-gradient(to bottom, #48a0e0 20%, #2b58a5);
  box-shadow: 0 -14px 14px #48a0e0;
  transition: all 0.3s ease-in-out;
}

优势:无需JS计算位置和宽度,窗口resize时自动适配,代码更简洁,性能更优。


方案二:优化原JS组件

如果必须保留独立的下划线组件,修复resize监听逻辑,优化性能和定位准确性:

修改后的Underline组件

import { useEffect, useState, useRef } from "react"
import { useLocation } from "react-router-dom"

export default function Underline() {
  const { pathname } = useLocation()
  const [underlineStyle, setUnderlineStyle] = useState({})
  // 导航栏容器的ref,用于计算相对定位偏移
  const navContainerRef = useRef(null)

  // 提取更新下划线位置的公共函数
  const updateUnderlinePosition = () => {
    let targetLink = document.querySelector(`a[href="${pathname}"]`)
    
    // 处理home链接的特殊逻辑
    if (targetLink?.getAttribute("id") !== null) {
      targetLink = document.querySelector("#home")
    }

    if (!targetLink) return

    // 计算相对于导航栏容器的left偏移(避免视口滚动影响)
    const containerRect = navContainerRef.current?.getBoundingClientRect() || { left: 0 }
    const linkRect = targetLink.getBoundingClientRect()

    setUnderlineStyle({
      width: `${targetLink.offsetWidth}px`,
      left: `${linkRect.left - containerRect.left}px`,
    })
  }

  useEffect(() => {
    // 初始化时更新位置
    updateUnderlinePosition()

    // 用requestAnimationFrame节流resize事件,避免频繁触发
    let resizeFrameId
    const handleResize = () => {
      cancelAnimationFrame(resizeFrameId)
      resizeFrameId = requestAnimationFrame(updateUnderlinePosition)
    }

    // 正确绑定resize监听(传函数引用,而非立即执行)
    window.addEventListener("resize", handleResize)

    return () => {
      window.removeEventListener("resize", handleResize)
      cancelAnimationFrame(resizeFrameId)
    }
  }, [pathname])

  // 需要将navContainerRef绑定到导航栏的父容器元素上
  return (
    <>
      {/* 假设导航栏容器是这个div,或者将ref传递给已有的导航容器 */}
      <div ref={navContainerRef} style={{ position: "relative" }}>
        {/* 导航链接放在这里 */}
      </div>
      <div id="underline" style={underlineStyle}></div>
    </>
  )
}

关键修复点:

  • 修复resize事件绑定:传递函数引用handleResize而非立即执行handleResize()
  • 用requestAnimationFrame节流resize事件,平衡响应速度和性能
  • 计算相对于导航栏容器的偏移量,避免视口滚动或resize时的定位偏差
  • 提取公共更新函数,在路由切换和resize时复用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:07:04