import React, { useState, useEffect, useRef } from 'react'; import './StickyNavExample.css'; /** * 最小化示例:实现滚动吸顶与分类高亮效果 */ const StickyNavExample = () => { // 分类数据 const categories = [ { id: 'section1', name: '分类一' }, { id: 'section2', name: '分类二' }, { id: 'section3', name: '分类三' }, { id: 'section4', name: '分类四' }, ]; // 状态管理 const [activeSection, setActiveSection] = useState(categories[0].id); const isManualScrollRef = useRef(false); const timerRef = useRef(null); // 监听滚动事件,更新当前活动分类 useEffect(() => { const handleScroll = () => { // 如果是手动点击导致的滚动,则跳过自动检测 if (isManualScrollRef.current) return; const stickyNav = document.querySelector('.sticky-nav'); const stickyHeight = stickyNav?.getBoundingClientRect().height || 0; const triggerOffset = stickyHeight + 20; // 触发点位置 // 遍历所有分类区块,检查哪个在视口中 categories.forEach(category => { const section = document.getElementById(category.id); if (section) { const rect = section.getBoundingClientRect(); // 当区块顶部进入触发点时,将其设为当前活动分类 if (rect.top <= triggerOffset && rect.bottom >= triggerOffset) { setActiveSection(category.id); } } }); }; // 添加滚动事件监听 window.addEventListener('scroll', handleScroll); // 组件卸载时移除事件监听 return () => window.removeEventListener('scroll', handleScroll); }, []); // 处理分类点击事件 const handleCategoryClick = (categoryId) => { // 清除之前的定时器 if (timerRef.current) { clearTimeout(timerRef.current); } // 设置为手动滚动,暂时禁用自动检测 isManualScrollRef.current = true; setActiveSection(categoryId); // 滚动到对应区块 const section = document.getElementById(categoryId); const stickyNav = document.querySelector('.sticky-nav'); if (section && stickyNav) { const stickyHeight = stickyNav.getBoundingClientRect().height; const sectionTop = section.offsetTop - stickyHeight; window.scrollTo({ top: sectionTop, behavior: 'smooth' }); } // 设置定时器,1秒后重新启用滚动检测 timerRef.current = setTimeout(() => { isManualScrollRef.current = false; }, 1000); }; return (
向下滚动查看效果
{/* 粘性导航区域 */}这是{category.name}的内容区域。滚动时,当此区域进入视口中间位置,对应的分类标签会自动高亮。
{/* 添加一些占位内容使页面可滚动 */}