diff --git a/ui components/sticknav/StickyNavExample.css b/ui components/sticknav/StickyNavExample.css new file mode 100644 index 0000000..25613b8 --- /dev/null +++ b/ui components/sticknav/StickyNavExample.css @@ -0,0 +1,75 @@ +/* 基础样式 */ +.container { + max-width: 800px; + margin: 0 auto; + padding: 20px; + font-family: Arial, sans-serif; +} + +.title { + margin-bottom: 10px; +} + +.subtitle { + margin-bottom: 40px; + color: #666; +} + +/* 粘性导航样式 */ +.sticky-nav { + position: sticky; + top: 0; + background-color: white; + padding: 15px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + z-index: 100; +} + +.search-box { + width: 100%; + padding: 10px; + margin-bottom: 15px; + border: 1px solid #ddd; + border-radius: 4px; +} + +.category-tabs { + display: flex; + gap: 10px; + overflow-x: auto; + padding-bottom: 5px; +} + +.category-tabs button { + padding: 8px 16px; + border: none; + background-color: #f0f0f0; + border-radius: 20px; + cursor: pointer; + white-space: nowrap; +} + +.category-tabs button.active { + background-color: #007bff; + color: white; +} + +/* 内容区域样式 */ +.content-section { + margin-top: 40px; + padding: 20px; + border: 1px solid #eee; + border-radius: 8px; +} + +.content-section h2 { + margin-bottom: 15px; +} + +/* 占位内容,使页面可滚动 */ +.placeholder { + height: 300px; + background: linear-gradient(to bottom, #f9f9f9, #e9e9e9); + margin-top: 20px; + border-radius: 8px; +} \ No newline at end of file diff --git a/ui components/sticknav/StickyNavExample.jsx b/ui components/sticknav/StickyNavExample.jsx new file mode 100644 index 0000000..8d40e01 --- /dev/null +++ b/ui components/sticknav/StickyNavExample.jsx @@ -0,0 +1,128 @@ +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 ( +
+ {/* 页面标题 */} +

滚动吸顶示例

+

向下滚动查看效果

+ + {/* 粘性导航区域 */} +
+ {/* 搜索框 */} + + + {/* 分类标签 */} +
+ {categories.map(category => ( + + ))} +
+
+ + {/* 内容区域 */} + {categories.map(category => ( +
+

{category.name}

+

这是{category.name}的内容区域。滚动时,当此区域进入视口中间位置,对应的分类标签会自动高亮。

+ {/* 添加一些占位内容使页面可滚动 */} +
+
+ ))} +
+ ); +}; + +export default StickyNavExample; \ No newline at end of file