You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:45:53