@aimerthyr/virtual-table 1.0.0 → 1.1.1-beta.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/CHANGELOG.md CHANGED
@@ -13,3 +13,24 @@
13
13
  - 完整的 TypeScript 类型支持
14
14
  - 基于 TanStack Table 和 TanStack Virtual
15
15
  - 内置基础样式
16
+
17
+ ## [1.1.0] - 2026-03-09
18
+
19
+ ### Changed
20
+
21
+ - 支持自定义footer、加载没有更多区域、自定义展开按钮
22
+ - 支持表头分组及行列单元格合并
23
+ - 支持动态配置表格主题
24
+ - VTbale 官网发布
25
+
26
+ ## [1.1.1] - 2026-03-10
27
+
28
+ ### Changed
29
+
30
+ - 调整部分类型定义为 interface 类型,方便做类型合并
31
+
32
+ ## [1.1.1-beta.1] - 2026-03-10
33
+
34
+ ### Changed
35
+
36
+ - 支持 v-model 类型提示
package/README.md CHANGED
@@ -1,14 +1,24 @@
1
1
  # @aimerthyr/virtual-table
2
2
 
3
- 高性能 Vue 3 虚拟滚动表格组件,基于 TanStack Table 和 TanStack Virtual 构建。
3
+ 基于 Vue 3TanStack Table 和 TanStack Virtual 的高性能虚拟滚动表格组件。
4
+
5
+ ## 介绍
6
+
7
+ `@aimerthyr/virtual-table` 是一个面向中大数据量场景的 Vue 3 表格组件,支持虚拟滚动、排序、筛选、分页、树形数据、展开行、行选择、固定表头、固定列、列宽调整等常用能力,并提供完整的 TypeScript 类型支持与插槽扩展能力。
4
8
 
5
9
  ## 特性
6
10
 
7
- - ✨ 虚拟滚动,支持大数据量渲染
8
- - 🎯 完整的表格功能:排序、筛选、分页、树结构、可展开、可选择、固定列、拖拽列等
9
- - 🎨 灵活的样式定制
10
- - 📦 TypeScript 支持
11
- - 🚀 高性能,基于 TanStack 生态
11
+ - 基于虚拟滚动实现大数据量高性能渲染
12
+ - 支持排序、筛选、分页、树形数据、展开行、行选择
13
+ - 支持固定表头、固定列、列宽调整
14
+ - 支持自定义单元格、自定义筛选、自定义分页、自定义主题
15
+ - 基于 Vue 3 Composition API 与 TypeScript 构建
16
+ - 底层依赖 TanStack Table 与 TanStack Virtual,扩展能力强
17
+
18
+ ## 官网
19
+
20
+ **在线地址:**
21
+ [https://aimerthyr.github.io/virtual-table/](https://aimerthyr.github.io/virtual-table/)
12
22
 
13
23
  ## 安装
14
24
 
@@ -23,36 +33,85 @@ npm install @aimerthyr/virtual-table
23
33
  yarn add @aimerthyr/virtual-table
24
34
  ```
25
35
 
26
- ### 基础用法
36
+ ## 依赖要求
37
+
38
+ - `vue >= 3.5.0`
39
+
40
+ ## 快速开始
41
+
42
+ ```ts
43
+ // main.ts 中导入
44
+ import '@aimerthyr/virtual-table/virtual-table.css'
45
+ ```
27
46
 
28
47
  ```vue
29
48
  <script setup lang="ts">
30
- import { VirtualTable } from '@aimerthyr/virtual-table'
49
+ import { ref } from 'vue'
50
+ import VTable, { type VTableColumn } from '@aimerthyr/virtual-table'
31
51
  import '@aimerthyr/virtual-table/virtual-table.css'
32
52
 
33
- const columns = [
34
- { columnKey: 'id', columnHeader: 'ID', columnWidth: 80 },
35
- { columnKey: 'name', columnHeader: '姓名', columnWidth: 150 },
36
- { columnKey: 'age', columnHeader: '年龄', columnWidth: 100 },
37
- ]
53
+ const data = ref([
54
+ { id: 1, name: '张三', age: 28, address: '北京市朝阳区' },
55
+ { id: 2, name: '李四', age: 32, address: '上海市浦东新区' },
56
+ { id: 3, name: '王五', age: 25, address: '广州市天河区' },
57
+ ])
38
58
 
39
- const data = [
40
- { id: 1, name: '张三', age: 25 },
41
- { id: 2, name: '李四', age: 30 },
42
- // ... 更多数据
59
+ const columns: VTableColumn[] = [
60
+ { columnKey: 'id', columnHeader: 'ID', columnWidth: 80 },
61
+ { columnKey: 'name', columnHeader: '姓名', columnWidth: 120 },
62
+ { columnKey: 'age', columnHeader: '年龄', columnWidth: 100, columnAlign: 'center' },
63
+ { columnKey: 'address', columnHeader: '地址' },
43
64
  ]
44
65
  </script>
45
66
 
46
67
  <template>
47
- <VirtualTable :columns="columns" :data="data" />
68
+ <!-- 建议设置 row-height,以获得更稳定的虚拟滚动体验 -->
69
+ <VTable :data="data" :columns="columns" :row-height="44" bordered />
48
70
  </template>
49
71
  ```
50
72
 
51
- ### 启用排序和筛选
73
+ ## 导入方式
74
+
75
+ ```ts
76
+ import VTable from '@aimerthyr/virtual-table'
77
+ ```
78
+
79
+ 或:
80
+
81
+ ```ts
82
+ import { VTable } from '@aimerthyr/virtual-table'
83
+ ```
84
+
85
+ 同时也支持按需导入类型:
86
+
87
+ ```ts
88
+ import type {
89
+ VTableChangeState,
90
+ VTableColumn,
91
+ VTableColumnSizingState,
92
+ VTableData,
93
+ VTableExpandedState,
94
+ VTableInstance,
95
+ VTablePaginationState,
96
+ VTableProps,
97
+ } from '@aimerthyr/virtual-table'
98
+ ```
99
+
100
+ ## 常见用法
101
+
102
+ ### 1. 启用排序和筛选
52
103
 
53
104
  ```vue
54
105
  <script setup lang="ts">
55
- const columns = [
106
+ import VTable, { type VTableColumn } from '@aimerthyr/virtual-table'
107
+ import '@aimerthyr/virtual-table/virtual-table.css'
108
+
109
+ const data = [
110
+ { id: 1, name: '张三', age: 28 },
111
+ { id: 2, name: '李四', age: 32 },
112
+ ]
113
+
114
+ const columns: VTableColumn[] = [
56
115
  {
57
116
  columnKey: 'name',
58
117
  columnHeader: '姓名',
@@ -60,46 +119,366 @@ const columns = [
60
119
  columnEnableSort: true,
61
120
  columnEnableFilter: true,
62
121
  },
63
- // ...
122
+ {
123
+ columnKey: 'age',
124
+ columnHeader: '年龄',
125
+ columnWidth: 100,
126
+ columnEnableSort: true,
127
+ },
64
128
  ]
65
129
  </script>
66
130
 
67
131
  <template>
68
- <VirtualTable :columns="columns" :data="data" />
132
+ <VTable :columns="columns" :data="data" />
69
133
  </template>
70
134
  ```
71
135
 
72
- ### 自定义单元格
136
+ ### 2. 自定义单元格
73
137
 
74
138
  ```vue
75
139
  <template>
76
- <VirtualTable :columns="columns" :data="data">
77
- <template #cell-name="{ row }">
78
- <strong>{{ row.original.name }}</strong>
140
+ <VTable :columns="columns" :data="data">
141
+ <template #bodyCell="{ columnKey, row }">
142
+ <strong v-if="columnKey === 'name'">{{ row.name }}</strong>
143
+ <template v-else>{{ row[columnKey] }}</template>
79
144
  </template>
80
- </VirtualTable>
145
+ </VTable>
81
146
  </template>
82
147
  ```
83
148
 
149
+ ### 3. 分页
150
+
151
+ ```vue
152
+ <script setup lang="ts">
153
+ import { ref } from 'vue'
154
+ import VTable, {
155
+ type VTableChangeState,
156
+ type VTableColumn,
157
+ type VTablePaginationState,
158
+ } from '@aimerthyr/virtual-table'
159
+
160
+ const loading = ref(false)
161
+ const totalCount = ref(200)
162
+
163
+ const pagination = ref<VTablePaginationState>({
164
+ pageIndex: 1,
165
+ pageSize: 10,
166
+ })
167
+
168
+ const tableData = ref<any[]>([])
169
+
170
+ const columns: VTableColumn[] = [
171
+ { columnKey: 'id', columnHeader: 'ID', columnWidth: 80 },
172
+ { columnKey: 'name', columnHeader: '姓名', columnWidth: 120 },
173
+ { columnKey: 'age', columnHeader: '年龄', columnWidth: 100 },
174
+ ]
175
+
176
+ const fetchData = async (page: number, pageSize: number) => {
177
+ loading.value = true
178
+
179
+ // 示例:实际项目中这里替换为你的接口请求
180
+ await new Promise((resolve) => setTimeout(resolve, 300))
181
+
182
+ const start = (page - 1) * pageSize
183
+ tableData.value = Array.from({ length: pageSize }, (_, i) => ({
184
+ id: start + i + 1,
185
+ name: `用户${start + i + 1}`,
186
+ age: 20 + ((start + i) % 20),
187
+ }))
188
+
189
+ loading.value = false
190
+ }
191
+
192
+ const handleTableChange = (state: VTableChangeState) => {
193
+ const { pageIndex, pageSize } = state.pagination
194
+ pagination.value = { pageIndex, pageSize }
195
+ fetchData(pageIndex, pageSize)
196
+ }
197
+
198
+ fetchData(pagination.value.pageIndex, pagination.value.pageSize)
199
+ </script>
200
+
201
+ <template>
202
+ <VTable
203
+ v-model:default-pagination="pagination"
204
+ :data="tableData"
205
+ :columns="columns"
206
+ :loading="loading"
207
+ :pagination-config="{
208
+ enabled: true,
209
+ total: totalCount,
210
+ placement: 'right',
211
+ }"
212
+ @table-change="handleTableChange"
213
+ />
214
+ </template>
215
+ ```
216
+
217
+ ### 4. 列宽调整
218
+
219
+ ```vue
220
+ <script setup lang="ts">
221
+ import { ref } from 'vue'
222
+ import VTable, { type VTableColumn, type VTableColumnSizingState } from '@aimerthyr/virtual-table'
223
+
224
+ const columnSizing = ref<VTableColumnSizingState>({})
225
+
226
+ const data = [
227
+ { id: 1, name: '张三', age: 28, email: 'zhangsan@example.com' },
228
+ { id: 2, name: '李四', age: 32, email: 'lisi@example.com' },
229
+ ]
230
+
231
+ const columns: VTableColumn[] = [
232
+ { columnKey: 'id', columnHeader: 'ID', columnWidth: 80, columnEnableResize: true },
233
+ { columnKey: 'name', columnHeader: '姓名', columnWidth: 120, columnEnableResize: true },
234
+ { columnKey: 'age', columnHeader: '年龄', columnWidth: 100, columnEnableResize: true },
235
+ { columnKey: 'email', columnHeader: '邮箱', columnEnableResize: true },
236
+ ]
237
+
238
+ const handleColumnSizingChange = (state: VTableColumnSizingState) => {
239
+ console.log('当前列宽状态:', state)
240
+ }
241
+ </script>
242
+
243
+ <template>
244
+ <VTable
245
+ v-model:default-column-sizing="columnSizing"
246
+ :data="data"
247
+ :columns="columns"
248
+ column-resize-mode="onEnd"
249
+ @column-sizing-change="handleColumnSizingChange"
250
+ />
251
+ </template>
252
+ ```
253
+
254
+ ### 5. 行选择
255
+
256
+ ```vue
257
+ <script setup lang="ts">
258
+ import VTable, { type VTableColumn } from '@aimerthyr/virtual-table'
259
+
260
+ const data = [
261
+ { id: 1, name: '张三', age: 28 },
262
+ { id: 2, name: '李四', age: 32 },
263
+ { id: 3, name: '王五', age: 25 },
264
+ ]
265
+
266
+ const columns: VTableColumn[] = [
267
+ { columnKey: 'name', columnHeader: '姓名' },
268
+ { columnKey: 'age', columnHeader: '年龄' },
269
+ ]
270
+
271
+ const handleSelectionChange = (rows: any[]) => {
272
+ console.log('选中的行:', rows)
273
+ }
274
+ </script>
275
+
276
+ <template>
277
+ <VTable
278
+ :data="data"
279
+ :columns="columns"
280
+ :row-selection-config="{
281
+ enabled: true,
282
+ onChange: handleSelectionChange,
283
+ }"
284
+ />
285
+ </template>
286
+ ```
287
+
288
+ ## Props
289
+
290
+ > 在 Vue 模板中请使用 `kebab-case`,例如 `rowHeight` 对应 `row-height`。
291
+
292
+ | 属性名 | 类型 | 默认值 | 说明 |
293
+ | ---------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------- |
294
+ | `data` | `TData[]` | `[]` | 表格数据源 |
295
+ | `columns` | `VTableColumn[]` | `[]` | 列配置 |
296
+ | `rowHeight` | `number` | `undefined` | 行高,建议设置以优化虚拟滚动表现 |
297
+ | `rowKey` | `string \| number \| ((row) => string \| number)` | `undefined` | 行唯一标识 |
298
+ | `loading` | `boolean` | `false` | 是否加载中 |
299
+ | `fixedHeader` | `boolean` | `true` | 是否固定表头 |
300
+ | `enableSortingRemoval` | `boolean` | `true` | 是否允许取消排序 |
301
+ | `bordered` | `boolean` | `false` | 是否显示边框 |
302
+ | `rowSelectionConfig` | `VTableRowSelectionConfig<TData>` | `{ enabled: false }` | 行选择配置 |
303
+ | `loadMoreConfig` | `VTableLoadMoreConfig` | `{ showNoMore: false, noMoreText: '没有更多了' }` | 滚动加载更多配置 |
304
+ | `paginationConfig` | `VTablePaginationConfig` | `{ enabled: false, placement: 'right', total: 0, mode: 'server' }` | 分页配置 |
305
+ | `treeConfig` | `VTableTreeConfig` | `{ enabled: false, childrenKey: 'children', indentSize: 16 }` | 树形结构配置 |
306
+ | `enableExpandRow` | `boolean` | `false` | 是否启用展开行 |
307
+ | `enableRowHover` | `boolean` | `true` | 是否启用行 hover 高亮 |
308
+ | `adaptiveColumnWidth` | `number` | `120` | 自适应列最小宽度 |
309
+ | `defaultExpandAllRows` | `boolean` | `false` | 是否默认展开所有行,仅初始化生效 |
310
+ | `columnResizeMode` | `'onChange' \| 'onEnd'` | `'onChange'` | 列宽调整模式 |
311
+ | `fixedFooter` | `boolean` | `false` | 是否固定表尾 |
312
+ | `themeConfig` | `VTableThemeConfig` | `{}` | 自定义主题配置 |
313
+ | `defaultCheckboxColumnWidth` | `number` | `40` | 默认 checkbox 列宽 |
314
+ | `defaultExpandColumnWidth` | `number` | `42` | 默认展开列宽 |
315
+ | `customRowAttributes` | `(row, rowIndex) => HTMLAttributes` | `() => ({})` | 自定义行属性 |
316
+ | `customHeaderCellAttributes` | `(column, colIndex) => ThHTMLAttributes` | `() => ({})` | 自定义表头单元格属性 |
317
+ | `customCellAttributes` | `(row, column, rowIndex, colIndex) => TdHTMLAttributes \| null` | `() => ({})` | 自定义表体单元格属性,返回 `colspan` 或 `rowspan` 为 `0` 时不渲染 |
318
+
319
+ ## 列配置 `VTableColumn`
320
+
321
+ | 属性名 | 类型 | 说明 |
322
+ | -------------------- | ------------------------------- | -------------------------- |
323
+ | `columnKey` | `string` | 列唯一 key,同时对应字段名 |
324
+ | `columnHeader` | `string \| VNode \| Function` | 列头内容 |
325
+ | `columnAlign` | `'left' \| 'center' \| 'right'` | 列对齐方式 |
326
+ | `columnWidth` | `number \| string` | 列宽,支持数字或百分比 |
327
+ | `columnEnableSort` | `boolean` | 是否启用排序 |
328
+ | `columnEnableFilter` | `boolean` | 是否启用筛选 |
329
+ | `columnCell` | `Function` | 单元格渲染函数 |
330
+ | `columnEnableResize` | `boolean` | 是否允许调整列宽 |
331
+ | `columnMaxWidth` | `number` | 列最大宽度 |
332
+ | `columnMinWidth` | `number` | 列最小宽度,默认 `50` |
333
+ | `columnChildren` | `VTableColumn[]` | 子列,用于表头分组 |
334
+
335
+ ## Events
336
+
337
+ > 在 Vue 模板中,事件请使用 `kebab-case` 形式监听。
338
+
339
+ | 事件名 | 回调参数 | 说明 |
340
+ | ---------------------- | ------------------------------------------ | ---------------------------------------- |
341
+ | `table-change` | `(state: VTableChangeState) => void` | 表格状态变化时触发,包括分页、排序、筛选 |
342
+ | `scroll-to-bottom` | `() => void` | 滚动到底部时触发 |
343
+ | `expanded-rows-change` | `(state: VTableExpandedState) => void` | 展开行变化时触发 |
344
+ | `column-sizing-change` | `(state: VTableColumnSizingState) => void` | 列宽调整时触发 |
345
+
346
+ ## Slots
347
+
348
+ | 插槽名 | 参数 | 说明 |
349
+ | ---------------------- | -------------------------------------------------------------- | ---------------------- |
350
+ | `customHeader` | `{ columns, table }` | 自定义整个表头 |
351
+ | `bodyCell` | `{ columnKey, column, row, rowIndex }` | 自定义单元格内容 |
352
+ | `headerCell` | `{ columnKey, column }` | 自定义表头单元格 |
353
+ | `customFilterIcon` | `{ columnKey, filtered, column }` | 自定义筛选图标 |
354
+ | `customFilterDropdown` | `{ confirm, reset, setFilterValue, column, filterModelValue }` | 自定义筛选下拉内容 |
355
+ | `expandedRowRender` | `{ row }` | 自定义展开行内容 |
356
+ | `customPopover` | `{ open, onOpenChange, trigger, content }` | 自定义 Popover |
357
+ | `customPagination` | `{ pageSize, pageIndex, total, onPageChange }` | 自定义分页器 |
358
+ | `customCheckbox` | `{ checked, disabled, indeterminate, onCheckedChange }` | 自定义复选框 |
359
+ | `customEmpty` | `-` | 自定义空状态 |
360
+ | `customLoadingIcon` | `-` | 自定义 loading 图标 |
361
+ | `customLoadNoMore` | `-` | 自定义“没有更多了”区域 |
362
+ | `customFooter` | `-` | 自定义表尾 |
363
+ | `customExpandIcon` | `{ expand, onExpandChange }` | 自定义展开图标 |
364
+
365
+ ## 实例方法
366
+
367
+ 组件暴露了以下实例能力:
368
+
369
+ | 方法名 | 类型 | 说明 |
370
+ | --------------- | -------------------------------------------------------- | ------------------- |
371
+ | `tanstackTable` | `Table<TData>` | TanStack Table 实例 |
372
+ | `scrollToIndex` | `(index: number, behavior?: 'auto' \| 'smooth') => void` | 滚动到指定行 |
373
+
374
+ 使用示例:
375
+
376
+ ```vue
377
+ <script setup lang="ts">
378
+ import { onMounted, ref } from 'vue'
379
+ import VTable, { type VTableInstance } from '@aimerthyr/virtual-table'
380
+
381
+ const tableRef = ref<VTableInstance | null>(null)
382
+
383
+ onMounted(() => {
384
+ tableRef.value?.scrollToIndex(20, 'smooth')
385
+ })
386
+ </script>
387
+
388
+ <template>
389
+ <VTable ref="tableRef" :data="data" :columns="columns" />
390
+ </template>
391
+ ```
392
+
393
+ ## 主题配置
394
+
395
+ `themeConfig` 支持覆盖默认主题配置,主要结构如下:
396
+
397
+ ```ts
398
+ type VTableThemeConfig = {
399
+ primaryColor?: string
400
+ header?: {
401
+ color?: string
402
+ backgroundColor?: string
403
+ borderRadius?: number
404
+ splitColor?: string
405
+ headerIconColor?: string
406
+ padding?: number
407
+ }
408
+ body?: {
409
+ color?: string
410
+ backgroundColor?: string
411
+ padding?: number
412
+ }
413
+ border?: {
414
+ borderStyle?: 'solid' | 'dashed'
415
+ borderColor?: string
416
+ }
417
+ rowHoverColor?: string
418
+ zIndex?: {
419
+ pinnedColumn?: number
420
+ fixedHeader?: number
421
+ fixedFooter?: number
422
+ }
423
+ }
424
+ ```
425
+
426
+ 示例:
427
+
428
+ ```vue
429
+ <template>
430
+ <VTable
431
+ :data="data"
432
+ :columns="columns"
433
+ :theme-config="{
434
+ primaryColor: '#1677ff',
435
+ header: {
436
+ backgroundColor: '#f5f7fa',
437
+ },
438
+ body: {
439
+ backgroundColor: '#ffffff',
440
+ },
441
+ rowHoverColor: '#f5f7fa',
442
+ }"
443
+ />
444
+ </template>
445
+ ```
446
+
447
+ ## 使用建议
448
+
449
+ - 大数据量场景下建议始终设置 `row-height`
450
+ - 如果需要滚动加载,建议配合 `loading` 与 `scroll-to-bottom` 一起使用,避免重复触发
451
+ - 分页模式下,如果是服务端分页,建议在 `table-change` 中统一处理分页、排序、筛选参数
452
+ - 如果有树形数据,优先配置 `tree-config`
453
+ - 如果需要自定义展开内容,使用 `enable-expand-row` 配合 `expandedRowRender`
454
+ - 如果列很多并出现横向滚动,建议配置 `adaptive-column-width`
455
+
456
+ ## 适用场景
457
+
458
+ - 后台管理系统数据表格
459
+ - 大数据量列表渲染
460
+ - 需要虚拟滚动优化的业务表格
461
+ - 需要可扩展插槽能力的 Vue 3 表格场景
462
+
84
463
  ## 开发
85
464
 
86
465
  ```bash
87
466
  # 安装依赖
88
467
  pnpm install
89
468
 
90
- # 开发模式
469
+ # 开发构建
91
470
  pnpm dev
92
471
 
93
- # 构建
472
+ # 生产构建
94
473
  pnpm build
95
474
  ```
96
475
 
97
- ## License
98
-
99
- MIT © [aimerthyr](https://github.com/aimerthyr)
100
-
101
476
  ## 相关链接
102
477
 
103
478
  - [GitHub](https://github.com/aimerthyr/virtual-table)
104
479
  - [TanStack Table](https://tanstack.com/table)
105
480
  - [TanStack Virtual](https://tanstack.com/virtual)
481
+
482
+ ## License
483
+
484
+ MIT