import { useEffect, useRef, useState } from 'react';
import './estimatedVirtualList.less';

const ScrollTable = (props) => {
  const { dataSource } = props;

  const [isScrolle, setIsScrolle] = useState(true);

  // 滚动速度,值越大,滚动越慢
  const speed = 10; // 单位是毫秒
  const scrollStep = 1; // 滚动步长
  const warper: any = useRef();
  const childDom1: any = useRef();
  const childDom2: any = useRef();
  const accumulatedScroll = useRef(0); // 累积滚动距离

  // 开始滚动
  useEffect(() => {
    if (!childDom2.current || !childDom1.current) return;

    // 多拷贝一层,让它无缝滚动
    childDom2.current.innerHTML = childDom1.current.innerHTML;

    let animationFrameId: any = null;
    let lastTime = 0;

    const scrollTable = (currentTime) => {
      if (isScrolle) {
        if (currentTime - lastTime >= speed) {
          lastTime = currentTime;
          accumulatedScroll.current += scrollStep;

          if (accumulatedScroll.current >= 1) {
            if (
              warper.current.scrollTop >=
              childDom1.current.scrollHeight - 1//临界点可能不会精确地触发所以需要减去重合的部分,如果出现闪动可以修改这个数据,一般调整几个像素就可以达到肉眼看不到跳动的程度了
            ) {
              warper.current.scrollTop = -childDom1.current.scrollHeight;
            } else {
              warper.current.scrollTop += Math.floor(accumulatedScroll.current);
              accumulatedScroll.current -= Math.floor(
                accumulatedScroll.current,
              );
            }
          }
        }
        animationFrameId = requestAnimationFrame(scrollTable);
      }
    };

    if (isScrolle) {
      animationFrameId = requestAnimationFrame(scrollTable);
    }

    return () => {
      if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
      }
    };
  }, [isScrolle]);

  const hoverHandler = (flag) => setIsScrolle(flag);

  return (
    <>
      <div className="parent" ref={warper}>
        <div className="child" ref={childDom1}>
          {dataSource.map((item) => {
            return (
              <div
                style={{
                  display: 'flex',
                  height: '45px',
                }}
                key={item.key}
                onMouseOver={() => hoverHandler(false)}
                onMouseLeave={() => hoverHandler(true)}
              >
                <span
                  style={{
                    display: 'block',
                    width: '50%',
                    lineHeight: '45px',
                    backgroundColor: '#215bc1',
                    color: '#fff',
                    textAlign: 'center',
                    border: '2px solid #032678',
                  }}
                >
                  {item.key}
                </span>
                <span
                  style={{
                    display: 'block',
                    width: '50%',
                    backgroundColor: '#215bc1',
                    color: '#fff',
                    lineHeight: '45px',
                    textAlign: 'center',
                    border: '2px solid #032678',
                  }}
                >
                  {item.area}
                </span>
              </div>
            );
          })}
        </div>
        <div className="child" ref={childDom2}></div>
      </div>
    </>
  );
};

export default ScrollTable;

对应的css

.parent {
  width: 100%;
  height: 100%;
  overflow-y: scroll;
  scrollbar-width: none;
  -ms-overflow-style: none;
  transition: none;
}

.parent::-webkit-scrollbar {
  display: none;
}

/* 设置的子盒子高度大于父盒子,产生溢出效果 */
.child {
  height: auto;
  scroll-behavior: smooth;

}

.child li {
  height: 50px;
  margin: 2px 0;
  background: #009678;
}

添加上数据就可以出现一个滚动列表

参考文章简单实现react 列表自动向上滚动,进入暂停,离开继续_react 图片垂直滚动 悬浮暂停-CSDN博客

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐