什么是虚拟列表
虚拟列表只对可视区域数据进行渲染,对非可视区域中的数据不渲染或部分渲染的技术,从而达到极高的渲染性能。
当服务端返回前端几万甚至十几万条记录需要前端展示,我们屏幕的可视区域高度为800px,列表项高度为40px,此时我们在屏幕中最多只能看到20个列表项,那么在渲染的时候,我们只需加载20条即可。
实现思路
虚拟列表实际上只对可视区域的数据项进行渲染
可视区域(visibleHeight)
: 根据屏幕可视区域动态计算或自定义固定高度数据渲染项(visibleCount)
:可视区域除以行高并向下取整startIndex
: 初始为0,听过滚动条偏移计算endIndex
:startIndex
+visibleCount
; 数据结束位置索引,可额外预加载几条数据
监听滚动条滚动事件,根据偏移距离计算startIndex
监听逻辑实现:
useEffect(() => {
const onScrollChange = (e: React.WheelEvent) => {
const top = (e.target as HTMLElement).scrollTop
const index = Math.floor(top / rowHeight)
setScrollTop(top)
setStartIndex(index ? index + 1 : 0)
}
virtualizedRef.current.addEventListener('scroll', onScrollChange)
return () => {
if (virtualizedRef.current) {
virtualizedRef.current.removeEventListener('scroll', onScrollChange)
}
}
}, [])
复制代码
HTML结构如下:
virtualized_placeholder
: 容器内占位,高度为列表总高度,撑满父容器,用于可视区域形成滚动条
<div ref={virtualizedRef} style={{ height: visibleHeight }}>
<table style={{ transform: `translate3d(0px, ${scrollTop}px, 0)` }}>
<thead>{...}</thead>
<tbody>{...}</tbody>
</table>
<div className="virtualized_placeholder" style={{ height: placeHeight }} />
</div>
复制代码
主要逻辑:
-
设置容器占位高度,计算可视区域数据项
-
监听容器滚动事件,计算偏移距离,startIndex,组件卸载移除滚动事件
-
startIndex作为deps依赖项,当发生改变更新展示数据
useEffect(() => {
const placeH = ((dataSource.length) * rowHeight) + rowHeight
setPlaceHeight(placeH)
setVisibleCount(Math.floor(visibleHeight / rowHeight) + 2)
}, [dataSource, rowHeight])
useEffect(() => {
const onScrollChange = (e: React.WheelEvent) => {
const top = (e.target as HTMLElement).scrollTop
const index = Math.floor(top / rowHeight)
setScrollTop(top)
setStartIndex(index ? index + 1 : 0)
}
virtualizedRef.current.addEventListener('scroll', onScrollChange)
return () => {
if (virtualizedRef.current) {
virtualizedRef.current.removeEventListener('scroll', onScrollChange)
}
}
}, [])
useEffect(() => {
const data = dataSource.slice(startIndex, startIndex + visibleCount)
setShowData(data)
}, [startIndex, visibleCount, dataSource])
复制代码
结果对比
加载3000条数据普通Table与虚拟列表结果对比(单位:ms)
通过Chrome的Performance工具来详细分析性能瓶颈
-
Recalculate Style
:样式计算,浏览器根据css选择器计算哪些元素应该应用哪些规则,确定每个元素具体的样式 -
Layout
:布局,知道元素应用哪些规则之后,浏览器开始计算它要占据的空间大小及其在屏幕的位置
参考
完整代码地址
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END