@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.
Files changed (46) hide show
  1. package/README.md +548 -0
  2. package/index.d.ts +311 -0
  3. package/index.esm.js +1771 -0
  4. package/index.esm.js.map +1 -0
  5. package/middleware/column-resize/index.d.ts +19 -0
  6. package/middleware/column-resize/index.js +130 -0
  7. package/middleware/column-resize/index.js.map +1 -0
  8. package/middleware/column-resize/styles.css +8 -0
  9. package/middleware/column-resize/styles.scss +10 -0
  10. package/middleware/empty/index.d.ts +10 -0
  11. package/middleware/empty/index.js +73 -0
  12. package/middleware/empty/index.js.map +1 -0
  13. package/middleware/expandable/index.d.ts +37 -0
  14. package/middleware/expandable/index.js +239 -0
  15. package/middleware/expandable/index.js.map +1 -0
  16. package/middleware/expandable/styles.css +49 -0
  17. package/middleware/expandable/styles.scss +73 -0
  18. package/middleware/horizontal-scroll-bar/index.d.ts +15 -0
  19. package/middleware/horizontal-scroll-bar/index.js +90 -0
  20. package/middleware/horizontal-scroll-bar/index.js.map +1 -0
  21. package/middleware/horizontal-scroll-bar/styles.css +11 -0
  22. package/middleware/horizontal-scroll-bar/styles.scss +13 -0
  23. package/middleware/loading/index.d.ts +7 -0
  24. package/middleware/loading/index.js +73 -0
  25. package/middleware/loading/index.js.map +1 -0
  26. package/middleware/loading/styles.css +17 -0
  27. package/middleware/loading/styles.scss +27 -0
  28. package/middleware/selection/index.d.ts +47 -0
  29. package/middleware/selection/index.js +282 -0
  30. package/middleware/selection/index.js.map +1 -0
  31. package/middleware/selection/styles.css +13 -0
  32. package/middleware/selection/styles.scss +20 -0
  33. package/middleware/summary/index.d.ts +36 -0
  34. package/middleware/summary/index.js +203 -0
  35. package/middleware/summary/index.js.map +1 -0
  36. package/middleware/summary/styles.css +36 -0
  37. package/middleware/summary/styles.scss +45 -0
  38. package/middleware/utils/getScrollbarSize.d.ts +5 -0
  39. package/middleware/utils/getScrollbarSize.js +15 -0
  40. package/middleware/utils/getScrollbarSize.js.map +1 -0
  41. package/middleware/utils/useControllableValue.d.ts +16 -0
  42. package/middleware/utils/useControllableValue.js +28 -0
  43. package/middleware/utils/useControllableValue.js.map +1 -0
  44. package/package.json +34 -0
  45. package/styles/table.css +142 -0
  46. 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
+ ![offset-layout](./docs/images/offset-top-layout.svg)
123
+
124
+ 例如上图所示,业务开发中的常见布局形式,绿色部分即为 Table 组件之前的**额外区域**,若这一部分的 DOM 高度较高,滚动会导致可视区域内容计算出错,导致 Table 存在空白部分。
125
+
126
+ 在虚拟列表的实现中,当滚动事件触发时,需要使用 `scrollTop` 与最接近滚动容器顶部的元素(锚点元素)位置进行比较,再得出最新的数据可视范围。
127
+
128
+ ![offset-scroll-top](./docs/images/offset-scroll-top.svg)
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
+ ![plugin 公式](./docs/images/plugin.svg)
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
+