react-tiny-virtual-list 原理理解及简单实现
插件提供的API
- width:整个列表的宽度
- height:可视区域的宽度,即整个内容的高度
- itemCount:数据列表的个数
- itemSize:单项内容的高度
- renderItem:渲染每一项内容
在渲染大批数据列表时可以使用改插件,实现原理是将在可视区域内渲染元素,在非可视区域内不渲染,但实际的占位高度存在。
import VirtualList from 'react-tiny-virtual-list'
const TestVirtualList = () => {
let data = new Array(50).fill(0);
let setProps = {
width: '50%', //整个列表的宽度
height: 500, //可视区域的宽度,即整个内容的高度
itemCount: data.length, //数据列表的个数
itemSize: 50, //单项内容的高度
renderItem: (data) => {
//渲染每一项内容
const { index, style } = data;
return (
<div key={index} style={{ ...style, backgroundColor: index % 2 === 1 ? 'red' : 'yellow' }}>
{index + 1}
</div>
);
},
};
return (
<div>
<VirtualList {...setProps} />
</div>
);
};
简单实现 react-tiny-virtual-list类似原理的方式
import React, { useRef, useState } from 'react';
const VirtualList = (props) => {
const { height, width, itemCount, itemSize, renderItem } = props;
const scrollBoxRef = useRef(null);
const [start, setStart] = useState(0);
const handleScroll = () => {
const { scrollTop } = scrollBoxRef.current;
const newStart = Math.floor(scrollTop / itemSize);
setStart(newStart);
};
let end = start + Math.floor(height / itemSize) + 1; //11
end = end > itemCount ? itemCount : end; //如果结束的索引已经越界了,到结束为止
//visibleList=[findex:0],.....(index:10}]
const visibleList = new Array(end - start)
.fill(0)
.map((item, index) => ({ index: start + index }));
let itemStyle = { position: 'absolute', left: 0, width: '100%', height: 50 };
return (
<div
style={{ overflow: 'auto', willChange: 'transform', height, width }}
ref={scrollBoxRef}
onScroll={handleScroll}
>
<div style={{ position: 'relative', width: '100%', height: `${itemCount*itemSize}px` }}>
{visibleList.map(({ index }) =>
renderItem({ index, style: { ...itemStyle, top: itemSize * index } }),
)}
</div>
</div>
);
};