虚拟滚动小tips

161 阅读2分钟

我们业务中,经常遇到过需要进行虚拟滚动的场景。 那么首先整体思路和图片懒加载类似,当触达达到可视区域,才进行元素渲染

方案

  1. 定高度
  2. 不定高度

定高度

1, 对于定高度相对好处理,首先,对于滚动区域,首先分为三个部分,一个是上缓冲区,另一个是下缓冲区,以及可视区域。 2. 制造缓冲区,都是为了能解决,滚动过快导致的白屏问题。

Screenshot 2024-08-25 230226.png

思路分析

  1. 首先确定一个最外层的container 容器。
  2. 之后设定三个区域,上缓冲区域,可视区域,下缓存区域。
  3. 计算每个元素距离最顶部容器的距离,以及各个区域的起始,结束序列号。
  4. 将上,下缓冲区内的元素,全部都塞进container 里面,通过序列,索引就能精确计算出,可视元素的具体相对位置。

疑问

  1. 需要渲染的节点越多,性能越差?
  2. 这个问题,要从渲染的速度,以及所需空间来考虑,一个是dom树的构建,布局树,重绘重流问题,以及过多的dom也会占用更多的内存空间,并且如果大量的dom没有及时清除,可能会导致内存泄露等问题。

demo代码示例

import React, { useEffect, useState } from "react";

type Props = {
  //可视区域高度
  height?: number;
  //容器宽度
  width?: number;
  //每一项高度
  itemSize?: number;
  // 总数量
  itemCount?: number;
  children?: React.ReactNode;
};

export const Lazy = (props: Props) => {
  const { itemSize = 10, height, itemCount, children, width } = props;
  const [scrollTop, setScrollTop] = useState(0);

  const handleScroll = (e: any) => {
    setScrollTop(e.currentTarget.scrollTop);
    
  };

  const getContainer = (scrollTop: number) => {
    //可视区域上边界
    let startIndex = Math.floor(scrollTop / parseInt(itemSize));
    // 缓冲区域上边界
    let cacheStartIndex = startIndex - 2;
    // 可视区能展示的元素的最大个数
    const numVisible = Math.ceil(height / itemSize);
    //下缓冲区结束边界
    let cacheEndIndex = startIndex + numVisible + 2;
    let items = [];
    for (let i = cacheStartIndex; i < cacheEndIndex; i++) {
      items.push(
        <div
          style={{ position: "absolute", top: i * itemSize, height: itemSize }}
        >
          {i}
        </div>
      );
    }
    return items;
  };


  return (
    <div
      style={{
        height: height,
        width: props.width,
        position: "relative",
        overflow: "auto",
      }}
      className="container"
      onScroll={(e) => {
        handleScroll(e);
      }}
    >
      {getContainer(scrollTop)}
    </div>
  );
};

不定高度待补充