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

React导航激活态冲突:滚动切换与点击跳转功能互斥

问题与解决方案

问题概述

需要实现两个功能:

  • 点击导航项平滑跳转至对应页面区块
  • 滚动页面到达新区块时,自动切换导航的激活状态

目前点击跳转功能正常,但基于yOffset设置激活态后,区块间无法正常切换,出现功能冲突。

问题分析

当前代码的核心冲突在于:

  1. 点击导航时调用onNav,既执行平滑滚动,又设置activeTab
  2. 滚动页面时,useEffect监听yOffset变化,再次调用onNav,这会重复触发滚动操作,同时覆盖点击时设置的activeTab,导致激活态混乱、区块切换异常

修复方案

将「滚动时更新激活态」和「点击跳转」的逻辑彻底分离:

  • 点击导航仅负责触发平滑滚动并设置激活态
  • 滚动页面时仅负责根据区块位置更新激活态,不再触发滚动操作

修改后的Nav组件代码

function Nav({ activeTab, setActiveTab, aboutRef, homeRef }) {
  const [yOffSet] = useScroll();
  const [isSticky, setIsSticky] = useState(false);

  useEffect(() => {
    // 处理导航栏吸顶逻辑
    setIsSticky(yOffSet > 400);
    
    // 仅根据滚动位置更新激活态,不触发滚动
    if (yOffSet < 600) {
      setActiveTab(`Home`);
    } else {
      setActiveTab(`About`);
    }
  }, [yOffSet, setActiveTab]);

  // 单独封装点击跳转逻辑
  const handleNavClick = (ref, link) => {
    ref.current.scrollIntoView({ behavior: "smooth" });
    setActiveTab(link);
  };

  return (
    <div ref={homeRef} className={`${styles.nav} container`}>
      <Logo />
      <div className={`${isSticky ? styles.sticky : ``} ${styles.links}`}>
        {navLinks.map((link) => (
          <NavLink
            onClick={() => handleNavClick(link === `Home` ? homeRef : aboutRef, link)}
            isActive={activeTab === link}
            linkName={link}
            key={link}
          />
        ))}
        <SocialLink className="margin-left-medium" name="Linkedin" />
        <SocialLink name="GitHub" />
      </div>
      <PrimaryButton message={`Get in touch`} />
    </div>
  );
}

修改后的App组件代码

function App() {
  const homeRef = useRef(null);
  const aboutRef = useRef(null);
  const [activeTab, setActiveTab] = useState(`Home`);

  return (
    <>
      <Nav
        activeTab={activeTab}
        setActiveTab={setActiveTab}
        homeRef={homeRef}
        aboutRef={aboutRef}
      />
      <Hero />
      <About aboutRef={aboutRef} />
    </>
  );
}

核心优化点

  • 拆分耦合逻辑:将原onNav拆分为点击专用的跳转函数,滚动时仅更新激活态,避免重复触发滚动
  • 简化吸顶判断:用setIsSticky(yOffSet > 400)替代冗余的多条件判断
  • 明确职责划分:点击操作负责跳转+激活,滚动操作仅负责激活,消除功能冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 18:33:39