antd table 滚动加载

背景

最近在工作中有一个列表的滚动加载功能需求,了解了一下发现antdtable是不支持滚动加载的,只有list支持。因为原来的业务代码是用table做的,为了不改变原来的代码,我打算自己写个table的滚动加载功能。

实现

想要实现一个滚动加载,目标就是实现对table的滚动行为进行监听。第一个想法就是获取Tabledom,然后对可滚动的table-body添加一个监听事件,这里我们利用useRef来获取dom。出现问题了,会报错,ts提示我们不能将MutableRefObject这个类型传递到tableprops中。

1
2
3
4
5
6
7
8
const target = useRef(null);
<Table
ref={target}
dataSource={dataSource}
columns={columns}
loading={tableLoading}
scroll={{ y: 200 }}
/>

既然Table不能传入ref,那在外面包一层div总行了吧,于是代码变成了这样

1
2
3
4
5
6
7
8
9
const target = useRef(null);
<div ref={target}>
<Table
dataSource={dataSource}
columns={columns}
loading={tableLoading}
scroll={{ y: 200 }}
/>
</div>

控制台打印一下target.current,可以获取dom对象,到这我们的第一步目的就达成了。

接下来我们在target.current中获取table-bodydom对象,并对table-body的滚动进行监听,然后通过条件crollHeight - scrollTop === clientHeight来判断滚动条是否滚到底了,滚到底了就去异步加载数据。完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import React, { useEffect, useState, useRef } from 'react';
import { Table } from 'antd';

const data = [
{
key: '1',
name: '胡彦斌',
age: 1,
address: '西湖区湖底公园1号',
},
{
key: '2',
name: '胡彦祖',
age: 2,
address: '西湖区湖底公园1号',
},
{
key: '3',
name: '胡彦斌',
age: 3,
address: '西湖区湖底公园1号',
},
{
key: '4',
name: '胡彦祖',
age: 4,
address: '西湖区湖底公园1号',
},
{
key: '5',
name: '胡彦斌',
age: 5,
address: '西湖区湖底公园1号',
},
{
key: '6',
name: '胡彦祖',
age: 6,
address: '西湖区湖底公园1号',
},
];

const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
];

const ScrollTable = () => {
const [dataSource, setDataSource] = useState(data);
const [tableLoading, setTableLoading] = useState(false);
const target = useRef(null);
useEffect(() => {
const dom = (target.current as HTMLElement | null)?.querySelector(
'.ant-table-body',
) as HTMLElement;
dom.addEventListener('scroll', () => scrollEvent());
return () => {
dom.removeEventListener('scroll', scrollEvent);
};
}, []);

const scrollEvent = () => {
const dom = (target.current as HTMLElement | null)?.querySelector(
'.ant-table-body',
) as HTMLElement;
if (dom.scrollHeight - dom.scrollTop === dom.clientHeight) {
// 在这里去获取并更新数据
setTableLoading(true);
setTimeout(() => {
console.log('已滚动到底部');
let arr: any = [];
setDataSource(arr);
setTableLoading(false);
}, 1000);
}
};

return (
<div
ref={target}
style={{ width: '70%', margin: 'auto', paddingTop: '100px' }}
>
<Table
dataSource={dataSource}
columns={columns}
loading={tableLoading}
scroll={{ y: 200 }}
/>
</div>
);
};

export default ScrollTable;

评论