基于GatsbyJS的单页网站菜单激活类名设置方法问询
如何在Gatsby单页滚动导航中给当前区块链接添加Active类
嘿,这个需求我在自己的Gatsby项目里刚实现过,给你分享两个实用的方案,都是亲测有效的:
方案一:用React原生钩子手动实现(自定义程度高)
如果想完全掌控滚动监听的逻辑,用useState+useEffect就能搞定,步骤如下:
- 先给页面每个区块加上对应的
id,比如:
<section id="home">...</section> <section id="about">...</section> <section id="portfolio">...</section>
- 在导航组件里,通过滚动监听判断当前视口对应的区块,动态设置active类:
import React, { useState, useEffect } from 'react'; const Navbar = () => { // 默认激活home区块 const [activeSection, setActiveSection] = useState('home'); const handleScroll = () => { // 获取所有带id的section元素 const sections = document.querySelectorAll('section[id]'); sections.forEach(section => { const sectionRect = section.getBoundingClientRect(); const sectionId = section.getAttribute('id'); // 这里的100是阈值,可以根据你的固定导航栏高度调整 // 当区块顶部距离视口顶部<=100px,且底部还没完全移出视口时,标记为active if (sectionRect.top <= 100 && sectionRect.bottom >= 0) { setActiveSection(sectionId); } }); }; // 组件挂载时添加滚动监听,卸载时移除 useEffect(() => { window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); return ( <nav className="navbar"> <ul> <li> <a href="#home" className={`nav-link ${activeSection === 'home' ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); // 平滑滚动到对应区块 document.getElementById('home').scrollIntoView({ behavior: 'smooth' }); }} > Home </a> </li> <li> <a href="#about" className={`nav-link ${activeSection === 'about' ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); document.getElementById('about').scrollIntoView({ behavior: 'smooth' }); }} > About </a> </li> <li> <a href="#portfolio" className={`nav-link ${activeSection === 'portfolio' ? 'active' : ''}`} onClick={(e) => { e.preventDefault(); document.getElementById('portfolio').scrollIntoView({ behavior: 'smooth' }); }} > Portfolio </a> </li> </ul> </nav> ); }; export default Navbar;
- 最后在CSS里给
.active类加高亮样式就行,比如:
.nav-link.active { color: #your-highlight-color; border-bottom: 2px solid #your-highlight-color; }
方案二:用react-scroll库(省心省力)
如果不想自己写滚动逻辑,react-scroll这个库已经封装好了滚动监听和active状态管理,用起来超方便:
- 先安装依赖:
npm install react-scroll # 或者用yarn yarn add react-scroll
- 在导航组件里使用库提供的
Link组件,它会自动识别当前滚动位置并添加active类:
import React from 'react'; import { Link } from 'react-scroll'; const Navbar = () => { return ( <nav className="navbar"> <ul> <li> <Link activeClass="active" // 激活时添加的类名 to="home" // 对应区块的id spy={true} // 开启滚动监听 smooth={true} // 平滑滚动 offset={-70} // 偏移量,根据你的固定导航栏高度调整,避免被遮挡 duration={500} // 滚动动画时长 className="nav-link" > Home </Link> </li> <li> <Link activeClass="active" to="about" spy={true} smooth={true} offset={-70} duration={500} className="nav-link" > About </Link> </li> <li> <Link activeClass="active" to="portfolio" spy={true} smooth={true} offset={-70} duration={500} className="nav-link" > Portfolio </Link> </li> </ul> </nav> ); }; export default Navbar;
- 同样,区块的
id要和Link的to属性对应上,然后给.active类加高亮样式就OK了。
小提示
- 如果你的导航栏是固定在顶部的,一定要调整阈值(方案一的100)或者偏移量(方案二的offset),不然区块会被导航栏挡住,active状态的切换也会不准。
- 方案一的逻辑可以根据需求自定义,比如你想让区块中间进入视口才激活,就调整判断条件里的数值。
内容的提问来源于stack exchange,提问作者Yavor
相关产品推荐
相关产品推荐

