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

NextJS 13单页作品集网站滚动时高亮当前导航项的实现

解决NextJS 13单页网站导航项高亮问题

你的单页网站靠锚点滚动切换区块,usePathname确实不适用,下面给你两种实用的解决方案:

方案一:点击+滚动自动高亮(推荐)

这个方案不仅在点击导航时高亮,滚动页面切换区块时也会自动更新高亮状态,体验更完整。

1. 编写导航组件

'use client';
import { useState, useEffect, useRef } from 'react';

const Navbar = () => {
  const [activeSection, setActiveSection] = useState('about'); // 默认高亮About区块
  const sectionsRef = useRef({});

  // 注册每个区块的DOM引用
  const registerSectionRef = (id, ref) => {
    if (ref) sectionsRef.current[id] = ref;
  };

  useEffect(() => {
    const observers = [];
    // 给每个区块绑定IntersectionObserver,监听是否进入视口
    Object.entries(sectionsRef.current).forEach(([id, section]) => {
      const observer = new IntersectionObserver(
        ([entry]) => {
          // 当区块50%进入视口时,更新活跃导航项
          if (entry.isIntersecting) setActiveSection(id);
        },
        { threshold: 0.5 }
      );
      observer.observe(section);
      observers.push(observer);
    });

    // 组件卸载时清理监听
    return () => observers.forEach(observer => observer.disconnect());
  }, []);

  // 导航点击逻辑:滚动到对应区块+更新高亮
  const handleNavClick = (id) => {
    setActiveSection(id);
    const target = document.getElementById(id);
    target?.scrollIntoView({ behavior: 'smooth' });
  };

  return (
    <nav className="flex gap-6 p-4 bg-gray-100">
      <button
        onClick={() => handleNavClick('about')}
        className={`px-3 py-1 rounded ${activeSection === 'about' ? 'bg-blue-500 text-white' : 'hover:bg-gray-200'}`}
      >
        About
      </button>
      <button
        onClick={() => handleNavClick('contact')}
        className={`px-3 py-1 rounded ${activeSection === 'contact' ? 'bg-blue-500 text-white' : 'hover:bg-gray-200'}`}
      >
        Contact
      </button>
    </nav>
  );
};

// 导出注册方法,供页面组件调用
export const registerSectionRef = Navbar.registerSectionRef;
export default Navbar;

2. 在页面组件中绑定区块引用

'use client';
import Navbar, { registerSectionRef } from './Navbar';

const Portfolio = () => {
  return (
    <div>
      <Navbar />
      <section id="about" ref={(el) => registerSectionRef('about', el)} className="h-screen flex items-center justify-center bg-gray-50">
        <h1>About Section</h1>
      </section>
      <section id="contact" ref={(el) => registerSectionRef('contact', el)} className="h-screen flex items-center justify-center bg-gray-100">
        <h1>Contact Section</h1>
      </section>
    </div>
  );
};

export default Portfolio;

方案二:仅点击时高亮(简洁版)

如果不需要滚动自动切换高亮,只处理点击事件即可,代码更简单:

'use client';
import { useState } from 'react';

const Navbar = () => {
  const [activeSection, setActiveSection] = useState('about');

  const handleNavClick = (e, id) => {
    e.preventDefault(); // 阻止默认锚点跳转行为
    setActiveSection(id);
    const target = document.getElementById(id);
    target?.scrollIntoView({ behavior: 'smooth' });
  };

  return (
    <nav className="flex gap-6 p-4 bg-gray-100">
      <a
        href="#about"
        onClick={(e) => handleNavClick(e, 'about')}
        className={`px-3 py-1 rounded ${activeSection === 'about' ? 'bg-blue-500 text-white' : 'hover:bg-gray-200'}`}
      >
        About
      </a>
      <a
        href="#contact"
        onClick={(e) => handleNavClick(e, 'contact')}
        className={`px-3 py-1 rounded ${activeSection === 'contact' ? 'bg-blue-500 text-white' : 'hover:bg-gray-200'}`}
      >
        Contact
      </a>
    </nav>
  );
};

export default Navbar;

高亮样式示例

不管用哪种方案,都需要给活跃状态加样式,比如:

/* 可以放在全局样式文件或组件内的style标签中 */
.active {
  background-color: #3b82f6;
  color: white;
  font-weight: 600;
  border-radius: 4px;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 15:43:11