需求背景
项目中有一个日志展示的页面,之前一直用的表格,后端也实现了分页,不过后面后端换服务后,不能分页,只能通过一个时间戳,前后查询。所以这种就不能用常规的分页方案解决,所以想到了无限滚动+懒加载,表格滚动到底时触发新的 append 请求,实现不断追加数据。
实现效果
解决方案
直接上代码
tsx
const Demo = () => {
const [tableData, setTableData] = useState([])
const [appendLoading, setAppendLoading] = useState(false);
const scrollRef = useRef({
left: 0,
top: 0,
});
const loadDataList = (time: string) => {
// 加载异步列表数据
}
const handleTableScroll = async (event: React.UIEvent<HTMLDivElement>) => {
const { scrollTop, clientHeight, scrollHeight, scrollLeft } =
event.target as HTMLDivElement;
// 垂直滚动 & 到底了
if (
Math.abs(scrollTop - scrollRef.current.top) > 0 &&
scrollTop + clientHeight >= scrollHeight
) {
setAppendLoading(true);
// 拿之前的最后一条数据的时间戳,获取追加数据列表
const appendList = await loadDataList(
tableData[tableData.length - 1].search_time
);
setAppendLoading(false);
setTableDate([...tableData, ...appendList]);
}
// 记录当前滚动信息
scrollRef.current = {
left: scrollLeft,
top: scrollTop,
};
};
return <Table
columns={columns}
dataSource={tableData}
rowKey="id"
loading={appendLoading}
pagination={false}
scroll={{ x: 1000, y: "calc(100vh - 300px)" }}
onScroll={handleTableScroll}
/>
}
核心逻辑详解
固定滚动高度,开启 table 的虚拟滚动,提升页面性能:
ts
scroll={{ x: 1000, y: "calc(100vh - 300px)" }}
使用 onScroll
事件判断触底,然后异步追加新数据:
ts
const handleTableScroll = async (event: React.UIEvent<HTMLDivElement>) => {
const { scrollTop, clientHeight, scrollHeight, scrollLeft } =
event.target as HTMLDivElement;
// 垂直滚动 & 到底了
if (
Math.abs(scrollTop - scrollRef.current.top) > 0 &&
scrollTop + clientHeight >= scrollHeight
) {
// .....
}
// 记录当前滚动信息
scrollRef.current = {
left: scrollLeft,
top: scrollTop,
};
};