@are-visual/virtual-table 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +548 -0
- package/index.d.ts +311 -0
- package/index.esm.js +1771 -0
- package/index.esm.js.map +1 -0
- package/middleware/column-resize/index.d.ts +19 -0
- package/middleware/column-resize/index.js +130 -0
- package/middleware/column-resize/index.js.map +1 -0
- package/middleware/column-resize/styles.css +8 -0
- package/middleware/column-resize/styles.scss +10 -0
- package/middleware/empty/index.d.ts +10 -0
- package/middleware/empty/index.js +73 -0
- package/middleware/empty/index.js.map +1 -0
- package/middleware/expandable/index.d.ts +37 -0
- package/middleware/expandable/index.js +239 -0
- package/middleware/expandable/index.js.map +1 -0
- package/middleware/expandable/styles.css +49 -0
- package/middleware/expandable/styles.scss +73 -0
- package/middleware/horizontal-scroll-bar/index.d.ts +15 -0
- package/middleware/horizontal-scroll-bar/index.js +90 -0
- package/middleware/horizontal-scroll-bar/index.js.map +1 -0
- package/middleware/horizontal-scroll-bar/styles.css +11 -0
- package/middleware/horizontal-scroll-bar/styles.scss +13 -0
- package/middleware/loading/index.d.ts +7 -0
- package/middleware/loading/index.js +73 -0
- package/middleware/loading/index.js.map +1 -0
- package/middleware/loading/styles.css +17 -0
- package/middleware/loading/styles.scss +27 -0
- package/middleware/selection/index.d.ts +47 -0
- package/middleware/selection/index.js +282 -0
- package/middleware/selection/index.js.map +1 -0
- package/middleware/selection/styles.css +13 -0
- package/middleware/selection/styles.scss +20 -0
- package/middleware/summary/index.d.ts +36 -0
- package/middleware/summary/index.js +203 -0
- package/middleware/summary/index.js.map +1 -0
- package/middleware/summary/styles.css +36 -0
- package/middleware/summary/styles.scss +45 -0
- package/middleware/utils/getScrollbarSize.d.ts +5 -0
- package/middleware/utils/getScrollbarSize.js +15 -0
- package/middleware/utils/getScrollbarSize.js.map +1 -0
- package/middleware/utils/useControllableValue.d.ts +16 -0
- package/middleware/utils/useControllableValue.js +28 -0
- package/middleware/utils/useControllableValue.js.map +1 -0
- package/package.json +34 -0
- package/styles/table.css +142 -0
- package/styles/table.scss +186 -0
package/README.md
ADDED
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
## Virtualize
|
|
2
|
+
|
|
3
|
+
### VirtualTable
|
|
4
|
+
|
|
5
|
+
` @are-visual/virtual-table` 是一个基于插件机制实现的虚拟表格组件,仅支持 React。
|
|
6
|
+
|
|
7
|
+
#### Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @are-visual/virtual-table
|
|
11
|
+
|
|
12
|
+
yarn add @are-visual/virtual-table
|
|
13
|
+
|
|
14
|
+
pnpm add @are-visual/virtual-table
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
#### Usage
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import type { ColumnType } from '@are-visual/virtual-table'
|
|
21
|
+
import { VirtualTable } from '@are-visual/virtual-table'
|
|
22
|
+
|
|
23
|
+
interface User {
|
|
24
|
+
id: number
|
|
25
|
+
name: string
|
|
26
|
+
age: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const dataSource: User[] = [
|
|
30
|
+
{ id: 1, name: 'Allen', age: 26 },
|
|
31
|
+
{ id: 2, name: 'Andrew', age: 43 },
|
|
32
|
+
{ id: 3, name: 'Max', age: 12 },
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
const columns: ColumnType<User>[] = [
|
|
36
|
+
{
|
|
37
|
+
dataIndex: 'id',
|
|
38
|
+
title: 'UID',
|
|
39
|
+
width: 100,
|
|
40
|
+
render(value) {
|
|
41
|
+
return `#${value}`
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
dataIndex: 'name',
|
|
46
|
+
title: 'Username',
|
|
47
|
+
width: 100,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
dataIndex: 'age',
|
|
51
|
+
title: 'Age',
|
|
52
|
+
align: 'right',
|
|
53
|
+
width: 100,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: 'actions',
|
|
57
|
+
title: 'Action',
|
|
58
|
+
width: 100,
|
|
59
|
+
render(value, record, index) {
|
|
60
|
+
return (
|
|
61
|
+
<button type="button">View details</button>
|
|
62
|
+
)
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
function App() {
|
|
68
|
+
return (
|
|
69
|
+
<VirtualTable
|
|
70
|
+
rowKey="id"
|
|
71
|
+
dataSource={dataSource}
|
|
72
|
+
columns={columns}
|
|
73
|
+
estimatedRowHeight={37}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### Columns 定义
|
|
80
|
+
|
|
81
|
+
| Prop Name | 说明 | 类型 | 默认值 | 版本 |
|
|
82
|
+
| ------------ | ------------------------------------------------------------ | ----------------------------------------- | ------ | ---- |
|
|
83
|
+
| key | React 需要的 key 属性,如果已经指定了唯一的 dataIndex,可忽略此属性 | Key | | |
|
|
84
|
+
| dataIndex | 指定 dataSource 中的 key 用于单元格内容展示 | string | | |
|
|
85
|
+
| className | 每列样式名称 | string | | |
|
|
86
|
+
| colSpan | **表头**列合并,设置为 0 时,不渲染 | number | | |
|
|
87
|
+
| title | 表头内容 | ReactNode | | |
|
|
88
|
+
| align | 单元格对齐方式 | `left` \|`right` \|`center` | | |
|
|
89
|
+
| minWidth | 列最小宽度 | number | | |
|
|
90
|
+
| width | 列宽度 | number \| string | | |
|
|
91
|
+
| fixed | 固定列 | `left` | `right` | | |
|
|
92
|
+
| render | 自定义单元格渲染内容 | (*value*, *record*, *index*) => ReactNode | | |
|
|
93
|
+
| onHeaderCell | 设置表头单元格属性 | (column, index) => TdHTMLAttributes | | |
|
|
94
|
+
| onCell | 设置单元格属性 | (column, index) => TdHTMLAttributes | | |
|
|
95
|
+
|
|
96
|
+
#### Table Props
|
|
97
|
+
|
|
98
|
+
| Prop Name | 说明 | 类型 | 默认值 | 版本 |
|
|
99
|
+
| -------------------- | ------------------------------------------------------- | --------------------------------------- | ------------------------------ | ---- |
|
|
100
|
+
| ref | 设置最外层 div ref | Ref\<HTMLDivElement\> | | |
|
|
101
|
+
| tableBodyRef | 设置 body 部分 table ref | Ref\<HTMLTableElement\> | | |
|
|
102
|
+
| className | 样式类名 | string | | |
|
|
103
|
+
| style | 样式 | CSSProperties | | |
|
|
104
|
+
| tableBodyClassName | body 样式类名 | string | | |
|
|
105
|
+
| tableBodyStyle | body 样式 | CSSProperties | | |
|
|
106
|
+
| columns | 表格列配置 | ColumnType[] | | |
|
|
107
|
+
| dataSource | 表格数据源 | object[] | | |
|
|
108
|
+
| rowKey | 表格行 key 的取值 | string | `key` | |
|
|
109
|
+
| estimatedRowHeight | 预计每行高度 | number | 46 | |
|
|
110
|
+
| estimatedColumnWidth | 预计每列宽度<br />需要横向虚拟化时,设置它 | number | | |
|
|
111
|
+
| overscanRows | 额外在首尾渲染数据条数 | number | 5 | |
|
|
112
|
+
| overscanColumns | 横向虚拟化时,在头和尾额外渲染多少列 | number | 3 | |
|
|
113
|
+
| stickyHeader | 表头吸顶<br />为 true 时 top 为 0,为 number 则是偏移量 | number \| boolean | | |
|
|
114
|
+
| pipeline | 插件实例 | TablePipeline | | |
|
|
115
|
+
| rowClassName | 表格行样式类名 | (*record*, *index*) => string | | |
|
|
116
|
+
| onRow | 设置行属性 | (*record*, *index*) => TdHTMLAttributes | | |
|
|
117
|
+
| getOffsetTop | 计算顶部偏移量 | () => number | 使用 最外层 div 计算 offsetTop | |
|
|
118
|
+
| virtualHeader | 开启表头虚拟滚动 | boolean | `false` | |
|
|
119
|
+
|
|
120
|
+
#### getOffsetTop
|
|
121
|
+
|
|
122
|
+

|
|
123
|
+
|
|
124
|
+
例如上图所示,业务开发中的常见布局形式,绿色部分即为 Table 组件之前的**额外区域**,若这一部分的 DOM 高度较高,滚动会导致可视区域内容计算出错,导致 Table 存在空白部分。
|
|
125
|
+
|
|
126
|
+
在虚拟列表的实现中,当滚动事件触发时,需要使用 `scrollTop` 与最接近滚动容器顶部的元素(锚点元素)位置进行比较,再得出最新的数据可视范围。
|
|
127
|
+
|
|
128
|
+

|
|
129
|
+
如上图所示,当 Table 与滚动容器的上边缘相交时,数据可视范围计算才可以开始计算。而正是因为额外区域的存在,导致 Table 与滚动容器上边缘相交前,可视数据范围的计算便已经触发了,造成 Table 中存在空白行。
|
|
130
|
+
|
|
131
|
+
所以,`@are-visual/virtual-table` 提供了 `getOffsetTop` 属性,用于得知额外区域的具体高度,这样在数据可视范围计算时才能避免这个问题。
|
|
132
|
+
|
|
133
|
+
一般来说,你不太需要关注 `getOffsetTop`,因为它有一个默认实现:使用 table 的 DOM 节点访问 offsetTop 属性作为偏移量。
|
|
134
|
+
|
|
135
|
+
`getOffsetTop` 总是会在滚动事件中反复调用。
|
|
136
|
+
|
|
137
|
+
> 关于 `getOffsetTop` 的默认实现是否会造成额外重排/性能影响,还有待验证。若你实在担心,可以设置 getOffsetTop 以覆盖默认实现。
|
|
138
|
+
|
|
139
|
+
#### 插件
|
|
140
|
+
|
|
141
|
+
`@are-visual/virtual-table` 提供一个 `useTablePipeline` hook 用于组合各种插件,为 Table 增加各式各样的功能。
|
|
142
|
+
|
|
143
|
+
目前插件列表:
|
|
144
|
+
|
|
145
|
+
- [columnResize 列宽调整](./packages/virtual-table/src/middleware/column-resize)
|
|
146
|
+
- [tableEmpty 空提示](./packages/virtual-table/src/middleware/empty)
|
|
147
|
+
- [tableExpandable 行展开](./packages/virtual-table/src/middleware/expandable)
|
|
148
|
+
- [horizontalScrollBar 水平滚动条](./packages/virtual-table/src/middleware/horizontal-scroll-bar)
|
|
149
|
+
- [tableLoading 加载状态](./packages/virtual-table/src/middleware/loading)
|
|
150
|
+
- [tableSelection 单选/多选](./packages/virtual-table/src/middleware/selection)
|
|
151
|
+
- [tableSummary 总结栏](./packages/virtual-table/src/middleware/summary)
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import '@are-visual/virtual-table/middleware/selection/styles.scss'
|
|
155
|
+
import { tableSelection } from '@are-visual/virtual-table/middleware/selection'
|
|
156
|
+
|
|
157
|
+
import '@are-visual/virtual-table/middleware/loading/styles.scss'
|
|
158
|
+
import { tableLoading } from '@are-visual/virtual-table/middleware/loading'
|
|
159
|
+
|
|
160
|
+
import { useState, type Key } from 'react'
|
|
161
|
+
import { useTablePipeline, VirtualTable } from '@are-visual/virtual-table'
|
|
162
|
+
|
|
163
|
+
function App() {
|
|
164
|
+
const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([])
|
|
165
|
+
|
|
166
|
+
const pipeline = useTablePipeline({
|
|
167
|
+
use: [
|
|
168
|
+
// 单选/多选插件
|
|
169
|
+
tableSelection({
|
|
170
|
+
selectedRowKeys,
|
|
171
|
+
onChange(selectedRowKeys, selectedRows, info) {
|
|
172
|
+
setSelectedRowKeys(selectedRowKeys)
|
|
173
|
+
},
|
|
174
|
+
}),
|
|
175
|
+
|
|
176
|
+
// loading 插件
|
|
177
|
+
tableLoading({ loading: false })
|
|
178
|
+
],
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<VirtualTable
|
|
183
|
+
pipeline={pipeline}
|
|
184
|
+
rowKey="id"
|
|
185
|
+
dataSource={dataSource}
|
|
186
|
+
columns={columns}
|
|
187
|
+
estimatedRowHeight={37}
|
|
188
|
+
/>
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
#### 插件顺序
|
|
194
|
+
|
|
195
|
+
你可以指定 `priority` 来编排插件的顺序,数字越大越靠后。
|
|
196
|
+
例如下面的 `columnResize`,其他插件修改 columns 后,才会轮到 columnResize 执行,这样它才能获取到最新最完整的 columns.
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
const pipeline = useTablePipeline({
|
|
200
|
+
use: [
|
|
201
|
+
tableLoading({ loading: true }),
|
|
202
|
+
|
|
203
|
+
{ priority: 100, hook: columnResize()},
|
|
204
|
+
],
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### 自定义插件
|
|
209
|
+
|
|
210
|
+
插件本身就是一个 react hook,它接受 `@are-visual/virtual-table` 传递的数据,处理再返回。
|
|
211
|
+
|
|
212
|
+
遵循下面这样的公式。当多个插件一起使用时,前一个插件返回的 context 会成为下一个插件所接收到的 context,所以这就是 pipeline。
|
|
213
|
+
|
|
214
|
+

|
|
215
|
+
|
|
216
|
+
##### 插件 context 定义
|
|
217
|
+
|
|
218
|
+
| key | 说明 | 类型 | 版本 |
|
|
219
|
+
| ------------ | ------------------------ | ------------ | ---- |
|
|
220
|
+
| dataSource | 表格数据源 | object[] | |
|
|
221
|
+
| columns | 表格列配置 | ColumnType[] | |
|
|
222
|
+
| rowKey | 表格行 key 的取值 | string | |
|
|
223
|
+
| estimatedRowHeight | 预计每行高度 | number | |
|
|
224
|
+
| rootRef | 最外层 div 元素 | RefObject\<HTMLDivElement\> | |
|
|
225
|
+
| headerWrapperRef | header 外层 div 元素 | RefObject\<HTMLDivElement\> | |
|
|
226
|
+
| bodyWrapperRef | body 外层 div 元素 | RefObject\<HTMLDivElement\> | |
|
|
227
|
+
| bodyRootRef | body 外层 table 节点 | RefObject\<HTMLTableElement\> | |
|
|
228
|
+
| bodyRef | tbody 元素 | RefObject\<HTMLTableSectionElement\> | |
|
|
229
|
+
| getScroller | 获取滚动容器 | () => ScrollElement \| undefined | |
|
|
230
|
+
| getOffsetTop | 计算顶部偏移量 | () => number | |
|
|
231
|
+
|
|
232
|
+
##### 插件返回值定义
|
|
233
|
+
|
|
234
|
+
| key | 说明 | 类型 | 版本 |
|
|
235
|
+
| ------------- | ------------------------ | --------------------------------------- | ---- |
|
|
236
|
+
| dataSource | 表格数据源 | object[] | |
|
|
237
|
+
| columns | 表格列配置 | ColumnType[] | |
|
|
238
|
+
| rowKey | 表格行 key 的取值 | string | |
|
|
239
|
+
| visibleRowSize | 当前虚拟化下所显示的行数 | number | |
|
|
240
|
+
| rowClassName | 自定义表格行 class | (*record*, *index*) => string | |
|
|
241
|
+
| onRow | 设置行属性 | (*record*, *index*) => TdHTMLAttributes | |
|
|
242
|
+
| render | 自定义 Table 外层渲染 | MiddlewareRender| |
|
|
243
|
+
| renderRoot | 自定义 div.virtual-table 渲染 | MiddlewareRenderRoot| |
|
|
244
|
+
| renderContent | | MiddlewareRenderContent| |
|
|
245
|
+
| renderHeaderWrapper | | MiddlewareRenderHeaderWrapper| |
|
|
246
|
+
| renderHeaderRoot | | MiddlewareRenderHeaderRoot| |
|
|
247
|
+
| renderHeader | Header 自定义渲染 | MiddlewareRenderHeader| |
|
|
248
|
+
| renderHeaderRow | 表头行自定义渲染 | MiddlewareRenderHeaderRow| |
|
|
249
|
+
| renderHeaderCell | 表头单元格自定义渲染 | MiddlewareRenderHeaderCell| |
|
|
250
|
+
| renderBodyWrapper | | MiddlewareRenderBodyWrapper| |
|
|
251
|
+
| renderBodyRoot | | MiddlewareRenderBodyRoot| |
|
|
252
|
+
| renderBody | 表格 body 自定义渲染 | MiddlewareRenderBody| |
|
|
253
|
+
| renderRow | 表格行自定义渲染 | MiddlewareRenderRow| |
|
|
254
|
+
| renderCell | 单元格自定义渲染 | MiddlewareRenderCell| |
|
|
255
|
+
|
|
256
|
+
> 出于性能考虑,请自行 memo render 函数
|
|
257
|
+
|
|
258
|
+
##### Render 结构
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
Context
|
|
262
|
+
└── render(<TableRoot />)
|
|
263
|
+
│
|
|
264
|
+
└── renderRoot(div.virtual-table)
|
|
265
|
+
│
|
|
266
|
+
└── renderContent(<><TableHeader/><TableBody/></>)
|
|
267
|
+
│
|
|
268
|
+
├── renderHeaderWrapper(<TableHeader />) div.virtual-table-header
|
|
269
|
+
│ │
|
|
270
|
+
│ └── renderHeaderRoot(<table />)
|
|
271
|
+
│ ├── colgroup
|
|
272
|
+
│ │
|
|
273
|
+
│ └── renderHeader(<thead />)
|
|
274
|
+
│ └── renderHeaderRow(<tr />)
|
|
275
|
+
│ └── renderHeaderCell(<th />)
|
|
276
|
+
│
|
|
277
|
+
└── renderBodyWrapper(<TableBody />) div.virtual-table-body-wrapper
|
|
278
|
+
│
|
|
279
|
+
└── renderBodyRoot(table.virtual-table-body)
|
|
280
|
+
├── colgroup
|
|
281
|
+
│
|
|
282
|
+
└── renderBody(<tbody />)
|
|
283
|
+
└── renderRow(<tr />)
|
|
284
|
+
└── renderCell(<td />)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
##### Render 类型签名
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
interface RenderOptions<T = any> {
|
|
291
|
+
column: ColumnType<T>
|
|
292
|
+
columnWidths: Map<Key, number>
|
|
293
|
+
rowIndex: number
|
|
294
|
+
columns: ColumnType<T>[]
|
|
295
|
+
rowData: T
|
|
296
|
+
columnDescriptor: ColumnDescriptor<T>[]
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
type MiddlewareRender<T = any> = (
|
|
300
|
+
children: ReactNode,
|
|
301
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
302
|
+
) => ReactNode
|
|
303
|
+
|
|
304
|
+
type MiddlewareRenderRoot<T = any> = (
|
|
305
|
+
children: ReactNode,
|
|
306
|
+
options: Omit<RenderOptions<T>, keyof RenderOptions<T>>
|
|
307
|
+
) => ReactNode
|
|
308
|
+
|
|
309
|
+
type MiddlewareRenderContent<T = any> = (
|
|
310
|
+
children: ReactNode,
|
|
311
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
312
|
+
) => ReactNode
|
|
313
|
+
|
|
314
|
+
type MiddlewareRenderHeaderWrapper<T = any> = (
|
|
315
|
+
children: ReactNode,
|
|
316
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
317
|
+
) => ReactNode
|
|
318
|
+
|
|
319
|
+
type MiddlewareRenderHeaderRoot<T = any> = (
|
|
320
|
+
children: ReactNode,
|
|
321
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
322
|
+
) => ReactNode
|
|
323
|
+
|
|
324
|
+
type MiddlewareRenderHeader<T = any> = (
|
|
325
|
+
children: ReactNode,
|
|
326
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
327
|
+
) => ReactNode
|
|
328
|
+
|
|
329
|
+
type MiddlewareRenderHeaderRow<T = any> = (
|
|
330
|
+
children: ReactNode,
|
|
331
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
332
|
+
) => ReactNode
|
|
333
|
+
|
|
334
|
+
type MiddlewareRenderHeaderCell<T = any> = (
|
|
335
|
+
children: ReactNode,
|
|
336
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor' | 'column' | 'columnWidths'>
|
|
337
|
+
) => ReactNode
|
|
338
|
+
|
|
339
|
+
type MiddlewareRenderBodyWrapper<T = any> = (
|
|
340
|
+
children: ReactNode,
|
|
341
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
342
|
+
) => ReactNode
|
|
343
|
+
|
|
344
|
+
type MiddlewareRenderBodyRoot<T = any> = (
|
|
345
|
+
children: ReactNode,
|
|
346
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
347
|
+
) => ReactNode
|
|
348
|
+
|
|
349
|
+
type MiddlewareRenderBody<T = any> = (
|
|
350
|
+
children: ReactNode,
|
|
351
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor'>
|
|
352
|
+
) => ReactNode
|
|
353
|
+
|
|
354
|
+
type MiddlewareRenderRow<T = any> = (
|
|
355
|
+
children: ReactNode,
|
|
356
|
+
options: Pick<RenderOptions<T>, 'columns' | 'columnDescriptor' | 'rowIndex' | 'rowData'>
|
|
357
|
+
) => ReactNode
|
|
358
|
+
|
|
359
|
+
type MiddlewareRenderCell<T = any> = (
|
|
360
|
+
children: ReactNode,
|
|
361
|
+
options: Pick<RenderOptions<T>, 'column'>
|
|
362
|
+
) => ReactNode
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
##### 插件编写
|
|
366
|
+
|
|
367
|
+
由于插件只是一个 react hook,可以直接这样写
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
import type { MiddlewareContext, MiddlewareResult } from '@are-visual/virtual-table'
|
|
371
|
+
|
|
372
|
+
function useLog<T = any>(ctx: MiddlewareContext<T>): MiddlewareResult<T> {
|
|
373
|
+
console.log('useLog 中间件被调用')
|
|
374
|
+
return ctx
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// 使用插件
|
|
378
|
+
const pipeline = useTablePipeline({
|
|
379
|
+
use: [
|
|
380
|
+
useLog,
|
|
381
|
+
],
|
|
382
|
+
})
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
携带参数
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
// 方式 1
|
|
389
|
+
const withLog = (options?: { prefix: string }) => {
|
|
390
|
+
function useLog<T = any>(ctx: MiddlewareContext<T>): MiddlewareResult<T> {
|
|
391
|
+
console.log(options?.prefix, 'useLog 中间件被调用')
|
|
392
|
+
return ctx
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return useLog
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// 使用插件
|
|
399
|
+
const pipeline = useTablePipeline({
|
|
400
|
+
use: [
|
|
401
|
+
withLog({ prefix: '🎯' }),
|
|
402
|
+
],
|
|
403
|
+
})
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
注意上述 withLog 的实现方式,一些与表格无关的渲染被触发时,withLog 依然会返回一个新的函数,这对于 diff 是有害的,总是会导致 Table 的额外渲染,如果你的插件不需要参数,那就没有影响,否则请使用 `createMiddleware` 创建插件。
|
|
407
|
+
|
|
408
|
+
##### 使用 createMiddleware 创建插件
|
|
409
|
+
|
|
410
|
+
```ts
|
|
411
|
+
import { createMiddleware } from '@are-visual/virtual-table'
|
|
412
|
+
|
|
413
|
+
function useLog<T = any>(ctx: MiddlewareContext<T>, options?: { prefix: string }): MiddlewareResult<T> {
|
|
414
|
+
console.log(options?.prefix, 'useLog 中间件被调用')
|
|
415
|
+
return ctx
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const withLog = createMiddleware(useLog)
|
|
419
|
+
|
|
420
|
+
// 使用插件
|
|
421
|
+
const pipeline = useTablePipeline({
|
|
422
|
+
use: [
|
|
423
|
+
withLog({ prefix: '🎯' }),
|
|
424
|
+
],
|
|
425
|
+
})
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
`createMiddleware` 会缓存插件的 options 参数,并在每一次渲染阶段进行一次比较,options 不同时才会返回新的函数,这样有利于避免 Table 进行一些额外的渲染。
|
|
429
|
+
|
|
430
|
+
#### 插件注意事项
|
|
431
|
+
|
|
432
|
+
由于插件是一个 react hook,所以也需要遵守 [react hooks 规则](https://react.dev/reference/rules/rules-of-hooks),不能在循环、判断条件中使用。
|
|
433
|
+
|
|
434
|
+
下面这种方式便是错误的,它违反了 hooks 规则,hook 不能位于判断条件中使用。
|
|
435
|
+
|
|
436
|
+
```tsx
|
|
437
|
+
const pipeline = useTablePipeline({
|
|
438
|
+
use: [
|
|
439
|
+
enableSelection ? tableSelection({}) : null,
|
|
440
|
+
loading ? tableLoading({}) : null,
|
|
441
|
+
],
|
|
442
|
+
})
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
#### Context Hooks
|
|
446
|
+
|
|
447
|
+
以下所列出的 hook 均与 Table 内部的 Context 有关,无法脱离 Provider 使用。
|
|
448
|
+
|
|
449
|
+
##### useContainerSize
|
|
450
|
+
|
|
451
|
+
读取 Context 传递的 Table 尺寸信息。
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
import { useContainerSize } from '@are-visual/virtual-table'
|
|
455
|
+
|
|
456
|
+
const {
|
|
457
|
+
scrollContainerHeight,
|
|
458
|
+
scrollContainerWidth,
|
|
459
|
+
tableHeight,
|
|
460
|
+
tableWidth,
|
|
461
|
+
} = useContainerSize()
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
##### useHorizontalScrollContext
|
|
465
|
+
|
|
466
|
+
当你自定义的插件需要同步水平滚动时,可以使用这个 hook。使用 `listen` 进行滚动同步。
|
|
467
|
+
|
|
468
|
+
可参考 [horizontalScrollBar 水平滚动条](./packages/virtual-table/src/middleware/horizontal-scroll-bar)的实现。
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
import { useHorizontalScrollContext } from '@are-visual/virtual-table'
|
|
472
|
+
|
|
473
|
+
const { listen, notify } = useHorizontalScrollContext()
|
|
474
|
+
|
|
475
|
+
const element = useRef()
|
|
476
|
+
useEffect(() => {
|
|
477
|
+
const node = element.current
|
|
478
|
+
|
|
479
|
+
if(node == null) return
|
|
480
|
+
|
|
481
|
+
// listen 会返回一个清除函数
|
|
482
|
+
return listen('union-key', (scrollLeft, targetNode) => {
|
|
483
|
+
node.scrollLeft = scrollLeft
|
|
484
|
+
})
|
|
485
|
+
}, [listen])
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
// element 滚动时,调用 notify 函数,同步其他容器
|
|
489
|
+
notify('union-key', element.scrollLeft, node)
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
##### useTableRowManager
|
|
493
|
+
|
|
494
|
+
此 hook 可以获取当前 Table 行的高度、更新行高。
|
|
495
|
+
|
|
496
|
+
可参考 [tableExpandable 行展开](./packages/virtual-table/src/middleware/expandable)的实现。
|
|
497
|
+
|
|
498
|
+
```tsx
|
|
499
|
+
import { useTableRowManager } from '@are-visual/virtual-table'
|
|
500
|
+
|
|
501
|
+
const { getRowHeightList, updateRowHeight } = useTableRowManager()
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
类型签名:
|
|
505
|
+
|
|
506
|
+
```ts
|
|
507
|
+
interface TableRowManagerContextType {
|
|
508
|
+
getRowHeightList: () => number[]
|
|
509
|
+
updateRowHeight: (index: number, height: number) => void
|
|
510
|
+
}
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
##### useColumnSizes
|
|
514
|
+
|
|
515
|
+
此 hook 可以获取当前 Table 每一列的宽度、更新列宽。
|
|
516
|
+
|
|
517
|
+
类型签名:
|
|
518
|
+
|
|
519
|
+
```ts
|
|
520
|
+
interface TableColumnsContextType {
|
|
521
|
+
widthList: Map<Key, number>
|
|
522
|
+
setWidthList: (value: Map<Key, number>) => void
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
##### useTableSticky
|
|
527
|
+
|
|
528
|
+
此 hook 可以获取每列 fixed 的值、sticky 位置。
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
interface StickyContextState {
|
|
532
|
+
size: Map<Key, number>
|
|
533
|
+
fixed: { key: Key, fixed: FixedType | undefined }[]
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
### 参考
|
|
540
|
+
|
|
541
|
+
[浅说虚拟列表的实现原理](https://github.com/dwqs/blog/issues/70)
|
|
542
|
+
|
|
543
|
+
[ali-react-table](https://ali-react-table.js.org/)
|
|
544
|
+
|
|
545
|
+
[rc-table](https://github.com/react-component/table)
|
|
546
|
+
|
|
547
|
+
[antd](https://ant.design/)
|
|
548
|
+
|