场景描述
我们经常有这样的场景,例如一个可以浏览的数据列表,数据量已经超出一般的百十来条,另外还需要勾选进行操作进行批量化操作等。
常规数据量下,服务端侧性能保障是以分页形式给出接口的,视觉角度肯定是希望连贯加载没有分页的操作感,在这样的场景下,我们需要使用虚拟滚动,尽可能在任意时刻内只关注可视窗口区域的数据的流畅展示,而忽视被遮挡区域,同时又不能影响数据的正常渲染,访问到底进行判断后拉取下一页数据,纵享丝滑。
虚拟滚动原理
白话讲就是活在当下,不要去回首昨天,也不要去操心明天。
虚拟滚动核心思路就是每次只渲染可视区域的列表数,当滚动后动态的追加元素并通过顶部padding来撑起整个滚动内容。
页面进行渲染的始终是固定的可视化区域的数据条数,而不是全部。
参考文章有很多很详细:
额外值知识点:
display: 'none' 是渲染的。不是不展示就不会影响性能。
同样数据量下数据比对
举例子:1个简单table,数据量小是很能感受出来区别的,数据量越大区分越大,模拟10W条简单表格数据为例。
在业务场景下,都会比范例要复杂,所以渲染成本更大,所以体验感受的上限更低。
非虚拟滚动: 渲染时长5283ms,渲染全部数据。
虚拟滚动: 渲染时长137ms,渲染固定条数。
滚动加载组件封装
思路:
1.监听是否滚动到底
2.判断当前页是否为最后一页
3.非最后一页pageNumber + 1,最后一页提示已经到底。
1
import React, { FC, useState } from 'react';
interface IProps {
4
maxBodyHeight?: number;
5
pageNumberAdd?: (any: any) => void;
6
pagination?: any;
7
}
8
9
const Index: FC = ({ maxBodyHeight, pageNumberAdd = () => {}, pagination, ...props }) => {
10
// 是否还有数据
11
const [isMore, setIsMore] = useState(true);
12
13
return (
14
<div
15
style={{ overflowY: 'scroll' }}
16
onScrollCapture={(e: any) => {
17
if (e.target.localName === 'div' && e.target.className === 'next-table-body') {
18
if (Math.round(e.target?.scrollTop) + e.target?.clientHeight === e.target?.scrollHeight) {
19
if (Math.ceil(pagination.total / pagination.pageSize) === pagination.pageNumber) {
20
setIsMore(false);
21
return null;
22
} else {
23
pageNumberAdd(Number(pagination.pageNumber) + 1);
24
}
25
}
26
}
27
}}
28
>
29
<Table
30
31
useVirtual
32
maxBodyHeight={maxBodyHeight}
33
fixedHeader
34
{...props}
35
/>
36
{!isMore ?
37
38
);
39
}
40
41
export default Index;
42
日常快速实现
1. fusion Table的虚拟滚动属性
结合fixedHeader和maxBodyHeight属性,可实现常规table指定高度的虚拟滚动。
2. fusion 虚拟滚动列表 VirtualList
使用与非列表的形式,例如大数量的标签,大数量的tag等。支持设置一屏数,缓冲区高度,以及跳转位置等。
组件给出了渲染思想:
zhuanlan.zhihu.com/p/55329238
3. antd Table
通过 react-window 引入虚拟滚动方案