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

如何在React中为单个Section实现垂直滚动指示器?

React 单个Section垂直滚动指示器实现方案

以下是针对单个Section实现垂直滚动填充指示器的具体步骤和代码:

核心思路

通过监听页面滚动事件,计算当前Section在视口中的滚动比例,动态更新指示器的填充高度,仅当用户滚动到目标Section范围内时,指示器才会触发填充动画。

完整代码实现

import { useEffect, useRef, useState } from 'react';

const ScrollIndicatorSection = () => {
  const sectionRef = useRef(null);
  const [scrollProgress, setScrollProgress] = useState(0);

  // 计算滚动进度的核心函数
  const handleScroll = () => {
    if (!sectionRef.current) return;

    const section = sectionRef.current;
    const rect = section.getBoundingClientRect();
    const sectionHeight = section.offsetHeight;
    const viewportHeight = window.innerHeight;
    const scrollTop = window.scrollY;
    const sectionTop = rect.top + scrollTop;
    const sectionBottom = sectionTop + sectionHeight;

    let progress = 0;
    // 当Section顶部进入视口,且底部未完全离开视口时计算进度
    if (scrollTop >= sectionTop && scrollTop <= sectionBottom - viewportHeight) {
      progress = (scrollTop - sectionTop) / (sectionHeight - viewportHeight);
    } 
    // 未进入视口时进度为0
    else if (scrollTop < sectionTop) {
      progress = 0;
    } 
    // 完全滚动出视口前进度固定为100%
    else if (scrollTop > sectionBottom - viewportHeight) {
      progress = 1;
    }

    setScrollProgress(Math.max(0, Math.min(1, progress)));
  };

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    // 初始化时触发一次,避免初始状态异常
    handleScroll();
    // 组件卸载时移除监听,防止内存泄漏
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  return (
    <section ref={sectionRef} style={{ position: 'relative', minHeight: '100vh', padding: '2rem' }}>
      {/* 垂直滚动指示器 */}
      <div style={{
        position: 'fixed',
        right: '20px',
        top: '50%',
        transform: 'translateY(-50%)',
        width: '4px',
        height: '150px',
        backgroundColor: '#e0e0e0',
        borderRadius: '2px'
      }}>
        <div style={{
          width: '100%',
          height: `${scrollProgress * 100}%`,
          backgroundColor: '#2196f3',
          borderRadius: '2px',
          transition: 'height 0.1s ease'
        }} />
      </div>

      {/* Section内容区域,可替换为你的实际内容 */}
      <div style={{ maxWidth: '800px', margin: '0 auto' }}>
        <h2>目标Section标题</h2>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
        <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>
        <p>Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</p>
        <p>Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.</p>
        <p>Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur?</p>
        <p>Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
      </div>
    </section>
  );
};

export default ScrollIndicatorSection;

关键逻辑说明

  • useRef:获取目标Section的DOM节点,用于后续计算元素的位置和尺寸。
  • useState:存储滚动进度值(范围0-1),用来控制指示器的填充高度。
  • handleScroll函数:
    1. 获取Section的位置信息和自身高度,结合视口高度计算Section的顶部、底部在文档中的位置。
    2. 根据当前滚动距离,判断Section所处的状态(未进入视口、滚动中、即将离开视口),计算对应的滚动进度。
  • useEffect:绑定滚动监听事件,组件卸载时移除监听,同时初始化触发一次进度计算,避免初始状态错误。

优化与自定义

  1. 性能优化:滚动事件触发频率高,可使用节流函数减少状态更新次数,比如引入lodash.throttle:
import throttle from 'lodash.throttle';

useEffect(() => {
  const throttledHandleScroll = throttle(handleScroll, 100);
  window.addEventListener('scroll', throttledHandleScroll);
  handleScroll();
  return () => window.removeEventListener('scroll', throttledHandleScroll);
}, []);
  1. 样式自定义:可调整指示器的位置(比如从fixed改为absolute,让指示器跟随Section)、尺寸、颜色、过渡动画时长等,适配你的页面风格。
  2. 多Section隔离:该组件仅作用于自身包裹的Section,不会影响页面其他区域,直接在需要的Section处引入即可。

内容的提问来源于stack exchange,提问作者user21662545

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 19:02:03