react实现简易版虚拟滚动

最近初学了react和大致了解了虚拟列表的实现,就手写实现一下练练手。

 主要功能要点:

  • 自适应容器
  • 虚拟滚动列表
  • 可配置组件

上代码:

import { useRef, useEffect, useState } from "react";
export default function Test() {
  const data = new Array(1000).fill(0).map((item, i) => i);
  const scrollConfig = {
    itemHeight: 20,
    maxCount: 15,
    total: data.length,
  };

  return (
    <div className="wrap">
      <VirtualScroll
        dataSource={data}
        scrollConfig={scrollConfig}
      ></VirtualScroll>
    </div>
  );
}
function VirtualScroll({ dataSource, scrollConfig }) {
  const scrollRef = useRef(null);
  let startIndex = 0;
  let endIndex = 0;
  const [myData, setMyData] = useState([]);
  const [y, setY] = useState(0);
  const contentWrapStyle = {
    height: scrollConfig.itemHeight * scrollConfig.total + "px",
  };
  const itemWrapStyle = {
    transform: ` translateY(${y})`,
  };
  useEffect(() => {
    const scrollDom = scrollRef.current;
    const handleScroll = () => {
      const top = scrollDom.scrollTop;
      const newY = top + "px";
      setY(newY);
      startIndex = Math.round(top / scrollConfig.itemHeight);
      endIndex = startIndex + scrollConfig.maxCount;
      const newData = dataSource.slice(startIndex, endIndex);
      setMyData(newData);
      console.log(top, startIndex, endIndex, myData);
    };

    scrollDom && scrollDom.addEventListener("scroll", handleScroll);

    return () => {
      scrollDom && scrollDom.removeEventListener("scroll", handleScroll);
    };
  }, []);

  return (
    <div className="scrollWrap" ref={scrollRef}>
      <div className="contentWrap" style={contentWrapStyle}></div>
      <div className="itemWrap" style={itemWrapStyle}>
        {myData.map((item, i) => (
          <ScrollItem
            content={item}
            key={i}
            itemHeight={scrollConfig.itemHeight}
          />
        ))}
      </div>
    </div>
  );
}
function ScrollItem({ content, itemHeight }) {
  return (
    <>
      <div style={{ height: itemHeight + "px" }}>{content}</div>
    </>
  );
}

css样式如下:

.wrap{
  width: 200px;
  height: 300px;
  margin: 30px auto;
}

.scrollWrap {
  background: #afece3;
  border: 1px solid #999;
  width: 100%;
  height: 100%;
  overflow-y: scroll;
  position: relative;
  left: 0;
  top: 0;
}
.itemWrap{
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

简易效果图:

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值