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
相关产品推荐
相关产品推荐

