React实现带比例区块头部的自定义滚动条技术问询
解决方案
1. 使用useRef管理动态区块引用
用useRef创建数组存储所有区块的DOM节点,替代document.querySelectorAll的DOM查询方式,更贴合React组件模型:
import { useRef } from 'react'; const sections = [ 'Lorem ...', 'Lorem ...', // 其他区块内容 ]; function SectionComponent(props) { return <div className="section">{props.section}</div>; } export default function SectionContainer() { // 初始化存储区块ref的数组 const sectionRefs = useRef([]); const handleScrollToSection = (index) => { const targetSection = sectionRefs.current[index]; if (targetSection) { targetSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }; return ( <> {sections.map((section, index) => ( <SectionComponent key={index} section={section} // 将每个区块的DOM元素存入ref数组 ref={(el) => (sectionRefs.current[index] = el)} /> ))} <div id="scrollbar"> {sections.map((_, index) => ( <div className="scroll-element" key={index} onClick={() => handleScrollToSection(index)} > {index} </div> ))} </div> </> ); }
2. 实现滚动条元素高度与区块成比例
计算每个区块高度占总高度的百分比,动态设置滚动条元素高度,同时监听窗口resize事件更新比例:
import { useRef, useState, useEffect } from 'react'; const sections = [ 'Lorem ...', 'Lorem ...', // 其他区块内容 ]; function SectionComponent(props) { return <div className="section">{props.section}</div>; } export default function SectionContainer() { const sectionRefs = useRef([]); // 存储每个滚动条元素的高度比例(百分比) const [scrollElementHeights, setScrollElementHeights] = useState([]); const calculateScrollElementHeights = () => { const sections = sectionRefs.current; if (!sections.length) return; // 计算所有区块的总高度 const totalHeight = sections.reduce((sum, section) => sum + section.offsetHeight, 0); // 计算每个区块对应的高度比例 const heights = sections.map(section => `${(section.offsetHeight / totalHeight) * 100}%`); setScrollElementHeights(heights); }; useEffect(() => { // 组件挂载后计算一次 calculateScrollElementHeights(); // 监听窗口resize,重新计算比例 window.addEventListener('resize', calculateScrollElementHeights); return () => window.removeEventListener('resize', calculateScrollElementHeights); }, []); const handleScrollToSection = (index) => { const targetSection = sectionRefs.current[index]; if (targetSection) { targetSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }; return ( <> {sections.map((section, index) => ( <SectionComponent key={index} section={section} ref={(el) => (sectionRefs.current[index] = el)} /> ))} <div id="scrollbar"> {sections.map((_, index) => ( <div className="scroll-element" key={index} onClick={() => handleScrollToSection(index)} // 应用计算出的高度比例 style={{ height: scrollElementHeights[index] || 'auto' }} > {index} </div> ))} </div> </> ); }
对应的CSS调整:
div.section { border: 2px solid black; width: 80%; margin: 1em auto; } div#scrollbar { position: fixed; width: 20px; height: 100%; top: 0; right: 0; background-color: aquamarine; display: flex; flex-direction: column; // 移除justify-content: space-around,让元素按高度比例自然排列 align-items: center; overflow: hidden; } div.scroll-element { padding: 0 5px; // 移除固定height,改用动态计算的比例 transform: rotate(-90deg); overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; cursor: pointer; }
说明
- 滚动条元素高度会根据对应区块占总区块高度的百分比自动调整,比如总高度1000px、某区块100px,则对应滚动条元素高度为10%
- 窗口大小变化时会重新计算比例,保证高度对应关系始终准确
useRef数组直接存储每个区块的DOM节点,比DOM查询更高效且符合React的组件设计逻辑
内容的提问来源于stack exchange,提问作者aabdulahad
相关产品推荐
相关产品推荐

