stk-table-vue 0.4.1 → 0.4.3
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 +32 -28
- package/lib/src/StkTable/StkTable.vue.d.ts +82 -60
- package/lib/src/StkTable/index.d.ts +0 -1
- package/lib/src/StkTable/types/index.d.ts +29 -11
- package/lib/src/StkTable/useAutoResize.d.ts +1 -0
- package/lib/src/StkTable/useColResize.d.ts +1 -0
- package/lib/src/StkTable/useFixedCol.d.ts +1 -0
- package/lib/src/StkTable/useFixedStyle.d.ts +1 -0
- package/lib/src/StkTable/useGetFixedColPosition.d.ts +1 -0
- package/lib/src/StkTable/useHighlight.d.ts +1 -0
- package/lib/src/StkTable/useKeyboardArrowScroll.d.ts +1 -0
- package/lib/src/StkTable/useThDrag.d.ts +1 -0
- package/lib/src/StkTable/useVirtualScroll.d.ts +12 -7
- package/lib/src/StkTable/utils/index.d.ts +3 -1
- package/lib/src/StkTable/utils/useTriggerRef.d.ts +1 -0
- package/lib/stk-table-vue.js +117 -60
- package/lib/style.css +7 -7
- package/package.json +64 -64
- package/src/StkTable/StkTable.vue +79 -35
- package/src/StkTable/style.less +22 -18
- package/src/StkTable/types/index.ts +31 -10
- package/src/StkTable/useFixedCol.ts +5 -5
- package/src/StkTable/useVirtualScroll.ts +49 -10
- package/src/StkTable/utils/index.ts +2 -6
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "stk-table-vue",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "Simple realtime virtual table for vue3 and vue2.7",
|
|
5
|
-
"main": "./lib/stk-table-vue.js",
|
|
6
|
-
"types": "./lib/src/StkTable/index.d.ts",
|
|
7
|
-
"packageManager": "pnpm@8.14.3",
|
|
8
|
-
"directories": {
|
|
9
|
-
"test": "test"
|
|
10
|
-
},
|
|
11
|
-
"type": "module",
|
|
12
|
-
"scripts": {
|
|
13
|
-
"dev": "vite",
|
|
14
|
-
"build": "vite build",
|
|
15
|
-
"test": "vitest"
|
|
16
|
-
},
|
|
17
|
-
"keywords": [
|
|
18
|
-
"virtual table",
|
|
19
|
-
"vue",
|
|
20
|
-
"vue2",
|
|
21
|
-
"vue3",
|
|
22
|
-
"highlight",
|
|
23
|
-
"sticky",
|
|
24
|
-
"virtual",
|
|
25
|
-
"table",
|
|
26
|
-
"list"
|
|
27
|
-
],
|
|
28
|
-
"files": [
|
|
29
|
-
"lib",
|
|
30
|
-
"src"
|
|
31
|
-
],
|
|
32
|
-
"author": "japlus",
|
|
33
|
-
"repository": {
|
|
34
|
-
"type": "git",
|
|
35
|
-
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
36
|
-
},
|
|
37
|
-
"license": "MIT",
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"@types/d3-interpolate": "^3.0.4",
|
|
40
|
-
"@types/node": "^20.
|
|
41
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
42
|
-
"@typescript-eslint/parser": "^
|
|
43
|
-
"@vitejs/plugin-vue": "^5.0.4",
|
|
44
|
-
"@vue/test-utils": "2.4.4",
|
|
45
|
-
"eslint": "^8.
|
|
46
|
-
"eslint-config-prettier": "^9.1.0",
|
|
47
|
-
"eslint-plugin-html": "^
|
|
48
|
-
"eslint-plugin-prettier": "^5.
|
|
49
|
-
"eslint-plugin-vue": "^9.
|
|
50
|
-
"happy-dom": "^12.10.3",
|
|
51
|
-
"less": "^4.2.0",
|
|
52
|
-
"postcss-discard-comments": "^6.0.
|
|
53
|
-
"postcss-preset-env": "^9.
|
|
54
|
-
"prettier": "^3.
|
|
55
|
-
"typescript": "^5.
|
|
56
|
-
"vite": "^5.2.
|
|
57
|
-
"vite-plugin-dts": "^3.
|
|
58
|
-
"vitest": "^1.
|
|
59
|
-
"vue": "^3.4.
|
|
60
|
-
"vue-eslint-parser": "^9.
|
|
61
|
-
},
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"d3-interpolate": "^3.0.1"
|
|
64
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "stk-table-vue",
|
|
3
|
+
"version": "0.4.3",
|
|
4
|
+
"description": "Simple realtime virtual table for vue3 and vue2.7",
|
|
5
|
+
"main": "./lib/stk-table-vue.js",
|
|
6
|
+
"types": "./lib/src/StkTable/index.d.ts",
|
|
7
|
+
"packageManager": "pnpm@8.14.3",
|
|
8
|
+
"directories": {
|
|
9
|
+
"test": "test"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "vite",
|
|
14
|
+
"build": "vite build",
|
|
15
|
+
"test": "vitest"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"virtual table",
|
|
19
|
+
"vue",
|
|
20
|
+
"vue2",
|
|
21
|
+
"vue3",
|
|
22
|
+
"highlight",
|
|
23
|
+
"sticky",
|
|
24
|
+
"virtual",
|
|
25
|
+
"table",
|
|
26
|
+
"list"
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
"lib",
|
|
30
|
+
"src"
|
|
31
|
+
],
|
|
32
|
+
"author": "japlus",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/d3-interpolate": "^3.0.4",
|
|
40
|
+
"@types/node": "^20.12.10",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
42
|
+
"@typescript-eslint/parser": "^7.7.0",
|
|
43
|
+
"@vitejs/plugin-vue": "^5.0.4",
|
|
44
|
+
"@vue/test-utils": "2.4.4",
|
|
45
|
+
"eslint": "^8.57.0",
|
|
46
|
+
"eslint-config-prettier": "^9.1.0",
|
|
47
|
+
"eslint-plugin-html": "^8.1.0",
|
|
48
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
49
|
+
"eslint-plugin-vue": "^9.25.0",
|
|
50
|
+
"happy-dom": "^12.10.3",
|
|
51
|
+
"less": "^4.2.0",
|
|
52
|
+
"postcss-discard-comments": "^6.0.2",
|
|
53
|
+
"postcss-preset-env": "^9.5.11",
|
|
54
|
+
"prettier": "^3.2.5",
|
|
55
|
+
"typescript": "^5.4.5",
|
|
56
|
+
"vite": "^5.2.11",
|
|
57
|
+
"vite-plugin-dts": "^3.9.1",
|
|
58
|
+
"vitest": "^1.6.0",
|
|
59
|
+
"vue": "^3.4.26",
|
|
60
|
+
"vue-eslint-parser": "^9.4.2"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"d3-interpolate": "^3.0.1"
|
|
64
|
+
}
|
|
65
65
|
}
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
'border-body-v': props.bordered === 'body-v',
|
|
16
16
|
stripe: props.stripe,
|
|
17
17
|
'cell-hover': props.cellHover,
|
|
18
|
+
'row-hover': props.rowHover,
|
|
19
|
+
'row-active': props.rowActive,
|
|
18
20
|
'text-overflow': props.showOverflow,
|
|
19
21
|
'header-text-overflow': props.showHeaderOverflow,
|
|
20
22
|
'fixed-relative-mode': isRelativeMode,
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
}"
|
|
46
48
|
>
|
|
47
49
|
<!-- transform: virtualX_on ? `translateX(${virtualScrollX.offsetLeft}px)` : null, 用transform控制虚拟滚动左边距,sticky会有问题 -->
|
|
48
|
-
<thead v-if="!headless">
|
|
50
|
+
<thead v-if="!headless" ref="theadRef">
|
|
49
51
|
<tr v-for="(row, rowIndex) in tableHeaders" :key="rowIndex" @contextmenu="e => onHeaderMenu(e)">
|
|
50
52
|
<!-- 这个th用于横向虚拟滚动表格左边距,width、maxWidth 用于兼容低版本浏览器 -->
|
|
51
53
|
<th
|
|
@@ -83,7 +85,7 @@
|
|
|
83
85
|
@dragover="onThDragOver"
|
|
84
86
|
>
|
|
85
87
|
<div class="table-header-cell-wrapper">
|
|
86
|
-
<component :is="col.customHeaderCell" v-if="col.customHeaderCell" :col="col" />
|
|
88
|
+
<component :is="col.customHeaderCell" v-if="col.customHeaderCell" :col="col" :colIndex="colIndex" :rowIndex="rowIndex" />
|
|
87
89
|
<template v-else-if="col.type === 'seq'">
|
|
88
90
|
<span class="table-header-title">{{ col.title }}</span>
|
|
89
91
|
</template>
|
|
@@ -142,8 +144,8 @@
|
|
|
142
144
|
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
143
145
|
<td v-if="virtualX_on && fixedMode && headless" class="virtual-x-left"></td>
|
|
144
146
|
<template v-if="fixedMode && headless">
|
|
145
|
-
<td v-for="col in virtualX_columnPart" :key="col.dataIndex" :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"></td
|
|
146
|
-
|
|
147
|
+
<td v-for="col in virtualX_columnPart" :key="col.dataIndex" :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"></td>
|
|
148
|
+
</template>
|
|
147
149
|
</tr>
|
|
148
150
|
</tbody>
|
|
149
151
|
<tbody class="stk-tbody-main">
|
|
@@ -182,14 +184,14 @@
|
|
|
182
184
|
:row="row"
|
|
183
185
|
:rowIndex="rowIndex"
|
|
184
186
|
:colIndex="colIndex"
|
|
185
|
-
:cellValue="row[col.dataIndex]"
|
|
187
|
+
:cellValue="row?.[col.dataIndex]"
|
|
186
188
|
/>
|
|
187
|
-
<div v-else class="table-cell-wrapper" :title="!col.type ? row[col.dataIndex] : ''">
|
|
189
|
+
<div v-else class="table-cell-wrapper" :title="!col.type ? row?.[col.dataIndex] : ''">
|
|
188
190
|
<template v-if="col.type === 'seq'">
|
|
189
191
|
{{ (props.seqConfig.startIndex || 0) + rowIndex + 1 }}
|
|
190
192
|
</template>
|
|
191
193
|
<template v-else>
|
|
192
|
-
{{ row[col.dataIndex] ?? getEmptyCellText(col, row) }}
|
|
194
|
+
{{ row?.[col.dataIndex] ?? getEmptyCellText(col, row) }}
|
|
193
195
|
</template>
|
|
194
196
|
</div>
|
|
195
197
|
</td>
|
|
@@ -208,11 +210,8 @@
|
|
|
208
210
|
<script setup lang="ts">
|
|
209
211
|
/**
|
|
210
212
|
* @author JA+
|
|
211
|
-
* 不支持低版本浏览器非虚拟滚动表格的表头固定,列固定,因为会卡。
|
|
212
213
|
* TODO:存在的问题:
|
|
213
214
|
* [] column.dataIndex 作为唯一键,不能重复
|
|
214
|
-
* [] 计算的高亮颜色,挂在数据源上对象上,若多个表格使用同一个数据源对象会有问题。需要深拷贝。(解决方案:获取组件uid)
|
|
215
|
-
* [] highlight-row 颜色不能恢复到active的颜色
|
|
216
215
|
*/
|
|
217
216
|
import { CSSProperties, computed, nextTick, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
|
|
218
217
|
import { DEFAULT_ROW_HEIGHT, IS_LEGACY_MODE } from './const';
|
|
@@ -229,7 +228,7 @@ import { useVirtualScroll } from './useVirtualScroll';
|
|
|
229
228
|
import { createStkTableId, getCalculatedColWidth, getColWidth, howDeepTheHeader, tableSort, transformWidthToStr } from './utils/index';
|
|
230
229
|
|
|
231
230
|
/** Generic stands for DataType */
|
|
232
|
-
type DT = any
|
|
231
|
+
type DT = Record<string | number, any>;
|
|
233
232
|
/** 自己生成实例id */
|
|
234
233
|
const stkTableId = createStkTableId();
|
|
235
234
|
/**
|
|
@@ -244,7 +243,7 @@ const props = withDefaults(
|
|
|
244
243
|
maxWidth?: string;
|
|
245
244
|
/** 斑马线条纹 */
|
|
246
245
|
stripe?: boolean;
|
|
247
|
-
/** 是否使用 table-layout:fixed */
|
|
246
|
+
/** 是否使用 table-layout:fixed(低版本浏览器需要设置table) */
|
|
248
247
|
fixedMode?: boolean;
|
|
249
248
|
/** 是否隐藏表头 */
|
|
250
249
|
headless?: boolean;
|
|
@@ -252,6 +251,12 @@ const props = withDefaults(
|
|
|
252
251
|
theme?: 'light' | 'dark';
|
|
253
252
|
/** 行高 */
|
|
254
253
|
rowHeight?: number;
|
|
254
|
+
/** 是否高亮鼠标悬浮的行 */
|
|
255
|
+
rowHover?: boolean;
|
|
256
|
+
/** 是否高亮选中的行 */
|
|
257
|
+
rowActive?: boolean;
|
|
258
|
+
/** 当前行再次点击否可以取消 */
|
|
259
|
+
rowCurrentRevokable?: boolean;
|
|
255
260
|
/** 表头行高。default = rowHeight */
|
|
256
261
|
headerRowHeight?: number | null;
|
|
257
262
|
/** 虚拟滚动 */
|
|
@@ -262,7 +267,7 @@ const props = withDefaults(
|
|
|
262
267
|
columns?: StkTableColumn<DT>[];
|
|
263
268
|
/** 表格数据源 */
|
|
264
269
|
dataSource?: DT[];
|
|
265
|
-
/** 行唯一键 */
|
|
270
|
+
/** 行唯一键 (行唯一值不能为undefined) */
|
|
266
271
|
rowKey?: UniqKeyProp;
|
|
267
272
|
/** 列唯一键 */
|
|
268
273
|
colKey?: UniqKeyProp;
|
|
@@ -278,7 +283,7 @@ const props = withDefaults(
|
|
|
278
283
|
showHeaderOverflow?: boolean;
|
|
279
284
|
/** 表体溢出是否展示... */
|
|
280
285
|
showOverflow?: boolean;
|
|
281
|
-
/** 是否增加行hover class */
|
|
286
|
+
/** 是否增加行hover class $*$ rename*/
|
|
282
287
|
showTrHoverClass?: boolean;
|
|
283
288
|
/** 是否高亮鼠标悬浮的单元格 */
|
|
284
289
|
cellHover?: boolean;
|
|
@@ -343,6 +348,9 @@ const props = withDefaults(
|
|
|
343
348
|
headless: false,
|
|
344
349
|
theme: 'light',
|
|
345
350
|
rowHeight: DEFAULT_ROW_HEIGHT,
|
|
351
|
+
rowHover: true,
|
|
352
|
+
rowActive: true,
|
|
353
|
+
rowCurrentRevokable: true,
|
|
346
354
|
headerRowHeight: null,
|
|
347
355
|
virtual: false,
|
|
348
356
|
virtualX: false,
|
|
@@ -390,9 +398,9 @@ const emits = defineEmits<{
|
|
|
390
398
|
(e: 'row-click', ev: MouseEvent, row: DT): void;
|
|
391
399
|
/**
|
|
392
400
|
* 选中一行触发。ev返回null表示不是点击事件触发的
|
|
393
|
-
* ```(ev: MouseEvent | null, row: DT, data: { select: boolean })```
|
|
401
|
+
* ```(ev: MouseEvent | null, row: DT | undefined, data: { select: boolean })```
|
|
394
402
|
*/
|
|
395
|
-
(e: 'current-change', ev: MouseEvent | null, row: DT, data: { select: boolean }): void;
|
|
403
|
+
(e: 'current-change', ev: MouseEvent | null, row: DT | undefined, data: { select: boolean }): void;
|
|
396
404
|
/**
|
|
397
405
|
* 行双击事件
|
|
398
406
|
* ```(ev: MouseEvent, row: DT)```
|
|
@@ -471,27 +479,31 @@ const emits = defineEmits<{
|
|
|
471
479
|
// }>();
|
|
472
480
|
|
|
473
481
|
const tableContainerRef = ref<HTMLDivElement>();
|
|
482
|
+
const theadRef = ref<HTMLElement>();
|
|
474
483
|
const colResizeIndicatorRef = ref<HTMLDivElement>();
|
|
475
484
|
|
|
476
485
|
/** 是否使用 relative 固定头和列 */
|
|
477
486
|
const isRelativeMode = ref(IS_LEGACY_MODE ? true : props.cellFixedMode === 'relative');
|
|
478
487
|
|
|
479
|
-
/**
|
|
480
|
-
|
|
488
|
+
/**
|
|
489
|
+
* 当前选中的一行
|
|
490
|
+
* - shallowRef: 使 currentRow.value === row 地址相同。防止rowKeyGen 的WeakMap key不一致。
|
|
491
|
+
*/
|
|
492
|
+
const currentRow = shallowRef<DT>();
|
|
481
493
|
/**
|
|
482
494
|
* 保存当前选中行的key<br>
|
|
483
495
|
* 原因:vue3 不用ref包dataSource时,row为原始对象,与currentItem(Ref)相比会不相等。
|
|
484
496
|
*/
|
|
485
497
|
const currentRowKey = ref<any>(null);
|
|
486
498
|
/** 当前hover行 */
|
|
487
|
-
let currentHoverRow: DT = null;
|
|
499
|
+
let currentHoverRow: DT | null = null;
|
|
488
500
|
/** 当前hover的行的key */
|
|
489
501
|
const currentHoverRowKey = ref(null);
|
|
490
502
|
/** 当前hover的列的key */
|
|
491
503
|
// const currentColHoverKey = ref(null);
|
|
492
504
|
|
|
493
505
|
/** 排序的列dataIndex*/
|
|
494
|
-
let sortCol = ref<
|
|
506
|
+
let sortCol = ref<keyof DT>();
|
|
495
507
|
let sortOrderIndex = ref(0);
|
|
496
508
|
|
|
497
509
|
/** 排序切换顺序 */
|
|
@@ -566,7 +578,7 @@ const {
|
|
|
566
578
|
initVirtualScrollX,
|
|
567
579
|
updateVirtualScrollY,
|
|
568
580
|
updateVirtualScrollX,
|
|
569
|
-
} = useVirtualScroll({ tableContainerRef, props, dataSourceCopy, tableHeaderLast, tableHeaders });
|
|
581
|
+
} = useVirtualScroll({ tableContainerRef, theadRef, props, dataSourceCopy, tableHeaderLast, tableHeaders });
|
|
570
582
|
|
|
571
583
|
/** 获取固定列的位置 */
|
|
572
584
|
const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeaders });
|
|
@@ -640,21 +652,23 @@ watch(
|
|
|
640
652
|
console.warn('invalid dataSource');
|
|
641
653
|
return;
|
|
642
654
|
}
|
|
655
|
+
/** 是否需要更新ScrollY,这里由于watch newValue与oldValue 的长度一样,因此需要这样使用 */
|
|
643
656
|
let needInitVirtualScrollY = false;
|
|
644
657
|
if (dataSourceCopy.value.length !== val.length) {
|
|
645
658
|
needInitVirtualScrollY = true;
|
|
646
659
|
}
|
|
647
660
|
dataSourceCopy.value = [...val];
|
|
648
661
|
// 数据长度没变则不计算虚拟滚动
|
|
649
|
-
if (needInitVirtualScrollY)
|
|
662
|
+
if (needInitVirtualScrollY) {
|
|
663
|
+
// 表格渲染后再执行。initVirtualScrollY 中有获取dom的操作。
|
|
664
|
+
nextTick(() => initVirtualScrollY());
|
|
665
|
+
}
|
|
650
666
|
|
|
651
667
|
if (sortCol.value) {
|
|
652
668
|
// 排序
|
|
653
669
|
const column = tableHeaderLast.value.find(it => it.dataIndex === sortCol.value);
|
|
654
670
|
onColumnSort(column, false);
|
|
655
671
|
}
|
|
656
|
-
// 是否需要
|
|
657
|
-
// updateFixedShadow();
|
|
658
672
|
},
|
|
659
673
|
{
|
|
660
674
|
deep: false,
|
|
@@ -771,11 +785,16 @@ function dealColumns() {
|
|
|
771
785
|
/**
|
|
772
786
|
* 行唯一值生成
|
|
773
787
|
*/
|
|
774
|
-
function rowKeyGen(row: DT) {
|
|
775
|
-
if (!row) return;
|
|
788
|
+
function rowKeyGen(row: DT | null | undefined) {
|
|
789
|
+
if (!row) return row;
|
|
776
790
|
let key = rowKeyGenStore.get(row);
|
|
777
791
|
if (!key) {
|
|
778
792
|
key = typeof props.rowKey === 'function' ? props.rowKey(row) : row[props.rowKey];
|
|
793
|
+
|
|
794
|
+
if (key === void 0) {
|
|
795
|
+
// key为undefined时,不应该高亮行。因此重新生成key
|
|
796
|
+
key = Math.random().toString();
|
|
797
|
+
}
|
|
779
798
|
rowKeyGenStore.set(row, key);
|
|
780
799
|
}
|
|
781
800
|
return key;
|
|
@@ -866,10 +885,15 @@ function onColumnSort(col?: StkTableColumn<DT>, click = true, options: { force?:
|
|
|
866
885
|
|
|
867
886
|
function onRowClick(e: MouseEvent, row: DT) {
|
|
868
887
|
emits('row-click', e, row);
|
|
869
|
-
|
|
870
|
-
if (
|
|
871
|
-
|
|
872
|
-
|
|
888
|
+
const isCurrentRow = props.rowKey ? currentRowKey.value === rowKeyGen(row) : currentRow.value === row;
|
|
889
|
+
if (isCurrentRow) {
|
|
890
|
+
if (!props.rowCurrentRevokable) {
|
|
891
|
+
// 不可取消
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
// 点击同一行,取消当前选中行。
|
|
895
|
+
currentRow.value = void 0;
|
|
896
|
+
currentRowKey.value = void 0;
|
|
873
897
|
emits('current-change', e, row, { select: false });
|
|
874
898
|
} else {
|
|
875
899
|
currentRow.value = row;
|
|
@@ -924,7 +948,6 @@ function onCellMouseOver(e: MouseEvent, row: DT, col: StkTableColumn<DT>) {
|
|
|
924
948
|
* @param e
|
|
925
949
|
*/
|
|
926
950
|
function onTableWheel(e: WheelEvent) {
|
|
927
|
-
e.preventDefault();
|
|
928
951
|
if (isColResizing.value) {
|
|
929
952
|
// 正在调整列宽时,不允许用户滚动
|
|
930
953
|
e.stopPropagation();
|
|
@@ -933,9 +956,30 @@ function onTableWheel(e: WheelEvent) {
|
|
|
933
956
|
// #region ---- 控制滚动,防止出现白屏--
|
|
934
957
|
const dom = tableContainerRef.value;
|
|
935
958
|
if (!dom) return;
|
|
959
|
+
const { containerHeight, scrollTop, scrollHeight, rowHeight } = virtualScroll.value;
|
|
960
|
+
const { containerWidth, scrollLeft, scrollWidth } = virtualScrollX.value;
|
|
961
|
+
/** 是否滚动在下面 */
|
|
962
|
+
const isScrollBottom = scrollHeight - containerHeight - scrollTop < rowHeight;
|
|
963
|
+
/** 是否滚动在右侧 */
|
|
964
|
+
const isScrollRight = scrollWidth - containerWidth - scrollLeft < 100;
|
|
936
965
|
const { deltaY, deltaX } = e;
|
|
937
|
-
|
|
938
|
-
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* 只有虚拟滚动时,才要用 wheel 代理scroll,防止滚动过快导致的白屏。
|
|
969
|
+
* 滚动条在边界情况时,not preventDefault 。因为会阻塞父级滚动条滚动。
|
|
970
|
+
*/
|
|
971
|
+
if (virtual_on && deltaY) {
|
|
972
|
+
if ((deltaY > 0 && !isScrollBottom) || (deltaY < 0 && scrollTop > 0)) {
|
|
973
|
+
e.preventDefault();
|
|
974
|
+
}
|
|
975
|
+
dom.scrollTop += deltaY;
|
|
976
|
+
}
|
|
977
|
+
if (virtualX_on && deltaX) {
|
|
978
|
+
if ((deltaX > 0 && !isScrollRight) || (deltaX < 0 && scrollLeft > 0)) {
|
|
979
|
+
e.preventDefault();
|
|
980
|
+
}
|
|
981
|
+
dom.scrollLeft += deltaX;
|
|
982
|
+
}
|
|
939
983
|
//#endregion
|
|
940
984
|
}
|
|
941
985
|
|
|
@@ -1024,7 +1068,7 @@ function setSorter(dataIndex: string, order: Order, option: { sortOption?: SortO
|
|
|
1024
1068
|
|
|
1025
1069
|
/** 重置排序 */
|
|
1026
1070
|
function resetSorter() {
|
|
1027
|
-
sortCol.value =
|
|
1071
|
+
sortCol.value = void 0;
|
|
1028
1072
|
sortOrderIndex.value = 0;
|
|
1029
1073
|
dataSourceCopy.value = [...props.dataSource];
|
|
1030
1074
|
}
|
|
@@ -1046,7 +1090,7 @@ function getTableData() {
|
|
|
1046
1090
|
}
|
|
1047
1091
|
|
|
1048
1092
|
/** 获取当前排序列的信息 */
|
|
1049
|
-
function getSortColumns(): SortState<DT
|
|
1093
|
+
function getSortColumns(): Partial<SortState<DT>>[] {
|
|
1050
1094
|
const sortOrder = sortSwitchOrder[sortOrderIndex.value];
|
|
1051
1095
|
if (!sortOrder) return [];
|
|
1052
1096
|
return [{ dataIndex: sortCol.value, order: sortOrder }];
|
package/src/StkTable/style.less
CHANGED
|
@@ -45,7 +45,13 @@
|
|
|
45
45
|
display: flex;
|
|
46
46
|
flex-direction: column;
|
|
47
47
|
box-sizing: border-box;
|
|
48
|
-
|
|
48
|
+
/**
|
|
49
|
+
* border-left: 此方案用于减少cell 中border-left 的css选择。同时利于多级表头border-left问题。利于横向滚动border-left
|
|
50
|
+
* - box-shadow inset 方案不生效,且占用属性。
|
|
51
|
+
* - outline 方案绘制在图形外
|
|
52
|
+
* - 绝对定位元素。需要根据滚动条位置动态计算。不合适。
|
|
53
|
+
* - sticky 定位方案需要占用位置。高度为0。
|
|
54
|
+
*/
|
|
49
55
|
border-left: 1px solid var(--border-color);
|
|
50
56
|
/* 下面border用于表格内容不满高度时,绘制表格边界线 */
|
|
51
57
|
background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
|
|
@@ -135,6 +141,15 @@
|
|
|
135
141
|
}
|
|
136
142
|
}
|
|
137
143
|
|
|
144
|
+
&.row-hover tbody tr:hover {
|
|
145
|
+
background-color: var(--tr-hover-bgc);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
&.row-active tbody tr.active {
|
|
150
|
+
background-color: var(--tr-active-bgc);
|
|
151
|
+
}
|
|
152
|
+
|
|
138
153
|
/* 单元格悬浮 */
|
|
139
154
|
&.cell-hover tbody td:hover {
|
|
140
155
|
box-shadow: inset 0 0 0 2px var(--td-hover-color);
|
|
@@ -252,29 +267,18 @@
|
|
|
252
267
|
|
|
253
268
|
}
|
|
254
269
|
|
|
255
|
-
thead {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
height: var(--header-row-height);
|
|
259
|
-
}
|
|
270
|
+
thead tr {
|
|
271
|
+
background-color: var(--th-bgc);
|
|
272
|
+
height: var(--header-row-height);
|
|
260
273
|
}
|
|
261
274
|
|
|
262
|
-
|
|
263
|
-
|
|
275
|
+
|
|
276
|
+
tbody tr {
|
|
264
277
|
background-color: var(--td-bgc);
|
|
265
278
|
height: var(--row-height);
|
|
266
|
-
/** 一行分层,有利于高亮行重绘
|
|
267
|
-
transform: translateZ(0);*/
|
|
268
|
-
|
|
269
|
-
&:hover {
|
|
270
|
-
background-color: var(--tr-hover-bgc);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
&.active {
|
|
274
|
-
background-color: var(--tr-active-bgc);
|
|
275
|
-
}
|
|
276
279
|
}
|
|
277
280
|
|
|
281
|
+
|
|
278
282
|
.virtual-x-left,
|
|
279
283
|
.virtual-x-right {
|
|
280
284
|
padding: 0;
|
|
@@ -5,16 +5,32 @@ export type Order = null | 'asc' | 'desc';
|
|
|
5
5
|
|
|
6
6
|
type Sorter<T> = boolean | ((data: T[], option: { order: Order; column: any }) => T[]);
|
|
7
7
|
|
|
8
|
-
export type
|
|
8
|
+
export type CustomCellProps<T extends Record<string, any>> = {
|
|
9
9
|
row: T;
|
|
10
10
|
col: StkTableColumn<T>;
|
|
11
11
|
/** row[col.dataIndex] 的值 */
|
|
12
12
|
cellValue: any;
|
|
13
13
|
rowIndex: number;
|
|
14
14
|
colIndex: number;
|
|
15
|
-
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* $*$自定义单元格渲染函数
|
|
19
|
+
* @deprecated
|
|
20
|
+
*/
|
|
21
|
+
export type CustomCellFunc<T extends Record<string, any>> = (props: CustomCellProps<T>) => VNode;
|
|
22
|
+
|
|
23
|
+
export type CustomHeaderCellProps<T extends Record<string, any>> = {
|
|
24
|
+
col: StkTableColumn<T>;
|
|
25
|
+
rowIndex: number;
|
|
26
|
+
colIndex: number;
|
|
27
|
+
};
|
|
16
28
|
|
|
17
|
-
|
|
29
|
+
/**
|
|
30
|
+
* $*$自定义表头渲染函数
|
|
31
|
+
* @deprecated
|
|
32
|
+
*/
|
|
33
|
+
export type CustomHeaderCellFunc<T extends Record<string, any>> = (props: CustomHeaderCellProps<T>) => VNode;
|
|
18
34
|
|
|
19
35
|
/** 表格列配置 */
|
|
20
36
|
export type StkTableColumn<T extends Record<string, any>> = {
|
|
@@ -55,17 +71,22 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
55
71
|
* 自定义 td 渲染内容。
|
|
56
72
|
*
|
|
57
73
|
* 组件prop入参:
|
|
58
|
-
*
|
|
59
|
-
*
|
|
74
|
+
* @param props.row 一行的记录。
|
|
75
|
+
* @param props.col 列配置
|
|
76
|
+
* @param props.cellValue row[col.dataIndex] 的值
|
|
77
|
+
* @param props.rowIndex 行索引
|
|
78
|
+
* @param props.colIndex 列索引
|
|
60
79
|
*/
|
|
61
|
-
customCell?: Component |
|
|
80
|
+
customCell?: Component<CustomCellProps<T>> | string;
|
|
62
81
|
/**
|
|
63
82
|
* 自定义 th 渲染内容
|
|
64
83
|
*
|
|
65
84
|
* 组件prop入参:
|
|
66
|
-
*
|
|
85
|
+
* @param props.col 列配置
|
|
86
|
+
* @param props.rowIndex 行索引
|
|
87
|
+
* @param props.colIndex 列索引
|
|
67
88
|
*/
|
|
68
|
-
customHeaderCell?: Component |
|
|
89
|
+
customHeaderCell?: Component<CustomHeaderCellProps<T>> | string;
|
|
69
90
|
/** 二级表头 */
|
|
70
91
|
children?: StkTableColumn<T>[];
|
|
71
92
|
/** 父节点引用 */
|
|
@@ -78,7 +99,7 @@ export type SortOption<T extends Record<string, any>> = Pick<StkTableColumn<T>,
|
|
|
78
99
|
|
|
79
100
|
/** 排序状态 */
|
|
80
101
|
export type SortState<T> = {
|
|
81
|
-
dataIndex: T;
|
|
102
|
+
dataIndex: keyof T;
|
|
82
103
|
order: null | 'asc' | 'desc';
|
|
83
104
|
sortType?: 'number' | 'string';
|
|
84
105
|
};
|
|
@@ -104,7 +125,7 @@ export type SortConfig<T extends Record<string, any>> = {
|
|
|
104
125
|
};
|
|
105
126
|
/**
|
|
106
127
|
* string排序是否使用 String.prototype.localCompare
|
|
107
|
-
* 默认true (
|
|
128
|
+
* 默认true ($*$应该false)
|
|
108
129
|
*/
|
|
109
130
|
stringLocaleCompare?: boolean;
|
|
110
131
|
};
|
|
@@ -76,17 +76,17 @@ export function useFixedCol<DT extends Record<string, any>>({
|
|
|
76
76
|
if (!props.fixedColShadow) return;
|
|
77
77
|
const fixedColsTemp: StkTableColumn<DT>[] = [];
|
|
78
78
|
const fixedShadowColsTemp: (StkTableColumn<DT> | null)[] = [];
|
|
79
|
-
let clientWidth, scrollWidth, scrollLeft;
|
|
79
|
+
let clientWidth, /* scrollWidth, */ scrollLeft;
|
|
80
80
|
|
|
81
81
|
if (virtualScrollX?.value) {
|
|
82
|
-
const { containerWidth: cw, scrollWidth: sw, scrollLeft: sl } = virtualScrollX.value;
|
|
82
|
+
const { containerWidth: cw, /* scrollWidth: sw, */ scrollLeft: sl } = virtualScrollX.value;
|
|
83
83
|
clientWidth = cw;
|
|
84
|
-
scrollWidth = sw;
|
|
84
|
+
// scrollWidth = sw;
|
|
85
85
|
scrollLeft = sl;
|
|
86
86
|
} else {
|
|
87
|
-
const { clientWidth: cw, scrollWidth: sw, scrollLeft: sl } = tableContainerRef.value as HTMLDivElement;
|
|
87
|
+
const { clientWidth: cw, /* scrollWidth: sw, */ scrollLeft: sl } = tableContainerRef.value as HTMLDivElement;
|
|
88
88
|
clientWidth = cw;
|
|
89
|
-
scrollWidth = sw;
|
|
89
|
+
// scrollWidth = sw;
|
|
90
90
|
scrollLeft = sl;
|
|
91
91
|
}
|
|
92
92
|
|