react实现scrollspy
React 实现 ScrollSpy 功能
ScrollSpy 是一种常见的 UI 交互效果,当用户滚动页面时,自动高亮显示当前可见区域对应的导航项。以下是实现 ScrollSpy 的几种方法:
使用 Intersection Observer API
Intersection Observer 是现代浏览器提供的 API,可以高效监听元素是否进入视口。

import { useEffect, useRef, useState } from 'react';
function ScrollSpy({ ids }) {
const [activeId, setActiveId] = useState('');
const observerRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setActiveId(entry.target.id);
}
});
},
{ rootMargin: '-50% 0px -50% 0px' }
);
ids.forEach((id) => {
const element = document.getElementById(id);
if (element) observer.observe(element);
});
observerRef.current = observer;
return () => observer.disconnect();
}, [ids]);
return (
<nav>
{ids.map((id) => (
<a
key={id}
href={`#${id}`}
style={{ color: activeId === id ? 'red' : 'black' }}
>
{id}
</a>
))}
</nav>
);
}
使用 scroll 事件监听
传统方法通过监听滚动事件计算元素位置。

import { useEffect, useState } from 'react';
function useScrollSpy(ids) {
const [activeId, setActiveId] = useState('');
useEffect(() => {
const handleScroll = () => {
const sections = ids.map((id) => document.getElementById(id));
const scrollPosition = window.scrollY + 100;
for (const section of sections) {
if (!section) continue;
const { offsetTop, offsetHeight } = section;
if (
scrollPosition >= offsetTop &&
scrollPosition < offsetTop + offsetHeight
) {
setActiveId(section.id);
break;
}
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [ids]);
return activeId;
}
使用第三方库
现有 React 库如 react-scrollspy 可快速实现功能:
npm install react-scrollspy
import Scrollspy from 'react-scrollspy';
function App() {
return (
<Scrollspy items={['section1', 'section2']} currentClassName="active">
<li><a href="#section1">Section 1</a></li>
</Scrollspy>
);
}
性能优化建议
对于大量内容页面,建议使用 Intersection Observer 而非 scroll 事件。设置合适的 rootMargin 可调整触发灵敏度,避免频繁计算。
动态内容场景下,需在内容变化时重新绑定观察目标。使用 useCallback 或依赖数组确保正确清理和重建监听器。






