基本信息
文件名称:ahooksuseVirtualList封装虚拟滚动列表.docx
文件大小:18.06 KB
总页数:7 页
更新时间:2025-05-22
总字数:约4.41千字
文档摘要

ahooksuseVirtualList封装虚拟滚动列表

目录简介实现原理具体实现思考总结

简介

提供虚拟化列表能力的Hook,用于解决展示海量数据渲染时首屏渲染缓慢和滚动卡顿问题。

详情可见官网,文章源代码可以点击这里。

实现原理

其实现原理监听外部容器的scroll事件以及其size发生变化的时候,触发计算逻辑算出内部容器的高度和marginTop值。

具体实现

其监听滚动逻辑如下:

//当外部容器的size发生变化的时候,触发计算逻辑

useEffect(()={

if(!size.width||!size.height){

return;

//重新计算逻辑

calculateRange();

},[size.width,size.height,list]);

//监听外部容器的scroll事件

useEventListener(

scroll,

e={

//如果是直接跳转,则不需要重新计算

if(scrollTriggerByScrollToFunc.current){

scrollTriggerByScrollToFunc.current=false;

return;

e.preventDefault();

//计算

calculateRange();

//外部容器

target:containerTarget,

);

其中calculateRange非常重要,它基本实现了虚拟滚动的主流程逻辑,其主要做了以下的事情:

获取到整个内部容器的高度totalHeight。根据外部容器的scrollTop算出已经滚过多少项,值为offset。根据外部容器高度以及当前的开始索引,获取到外部容器能承载的个数visibleCount。并根据overscan(视区上、下额外展示的DOM节点数量)计算出开始索引(start)和(end)。根据开始索引获取到其距离最开始的距离(offsetTop)。最后根据offsetTop和totalHeight设置内部容器的高度和marginTop值。

变量很多,可以结合下图,会比较清晰理解:

代码如下:

//计算范围,由哪个开始,哪个结束

constcalculateRange=()={

//获取外部和内部容器

//外部容器

constcontainer=getTargetElement(containerTarget);

//内部容器

constwrapper=getTargetElement(wrapperTarget);

if(containerwrapper){

const{

//滚动距离顶部的距离。设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离

scrollTop,

//内容可视区域的高度

clientHeight,

}=container;

//根据外部容器的scrollTop算出已经“滚过”多少项

constoffset=getOffset(scrollTop);

//可视区域的DOM个数

constvisibleCount=getVisibleCount(clientHeight,offset);

//开始的下标

conststart=Math.max(0,offset-overscan);

//结束的下标

constend=Math.min(list.length,offset+visibleCount+overscan);

//获取上方高度

constoffsetTop=getDistanceTop(start);

//设置内部容器的高度,总的高度-上方高度

//@ts-ignore

wrapper.style.height=totalHeight-offsetTop+px;

//margintop为上方高度

//@ts-ignore

wrapper.style.marginTop=offsetTop+px;

//设置最后显示的List

setTargetList(

list.slice(start,end).map((ele,index)=({