stk-table-vue 0.0.1-beta.6 → 0.0.1-beta.7
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 +4 -27
- package/lib/src/StkTable/StkTable.vue.d.ts +3 -6
- package/lib/src/StkTable/types/index.d.ts +3 -3
- package/lib/src/StkTable/useKeyboardArrowScroll.d.ts +14 -0
- package/lib/src/StkTable/useVirtualScroll.d.ts +32 -0
- package/lib/stk-table-vue.js +64 -11
- package/lib/style.css +238 -236
- package/package.json +4 -4
- package/src/StkTable/StkTable.vue +63 -63
- package/src/StkTable/types/index.ts +2 -2
- package/src/StkTable/useKeyboardArrowScroll.ts +66 -0
- package/src/StkTable/useVirtualScroll.ts +55 -9
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@ js体积(未压缩41kb)
|
|
|
11
11
|
* [x] 表头列宽拖动。
|
|
12
12
|
* [x] 多级表头。(不支持横向虚拟滚动)
|
|
13
13
|
* [x] 支持table-layout: fixed 配置。
|
|
14
|
-
* []
|
|
14
|
+
* [x] 鼠标悬浮在表格上,键盘上下左右滚动虚拟表格
|
|
15
|
+
* [] 列固定阴影
|
|
15
16
|
|
|
16
17
|
## Usage
|
|
17
18
|
> npm install stk-table-vue
|
|
@@ -36,80 +37,57 @@ const stkTable = ref<InstanceType<typeof StkTable>>();
|
|
|
36
37
|
```ts
|
|
37
38
|
export type StkProps = Partial<{
|
|
38
39
|
width: string;
|
|
39
|
-
|
|
40
40
|
/** 最小表格宽度 */
|
|
41
41
|
minWidth: string;
|
|
42
|
-
|
|
43
42
|
/** 表格最大宽度*/
|
|
44
43
|
maxWidth: string;
|
|
45
|
-
|
|
46
44
|
/** 是否使用 table-layout:fixed */
|
|
47
45
|
fixedMode: boolean;
|
|
48
|
-
|
|
49
46
|
/** 是否隐藏表头 */
|
|
50
47
|
headless: boolean;
|
|
51
|
-
|
|
52
48
|
/** 主题,亮、暗 */
|
|
53
49
|
theme: 'light' | 'dark';
|
|
54
|
-
|
|
55
50
|
/** 虚拟滚动 */
|
|
56
51
|
virtual: boolean;
|
|
57
|
-
|
|
58
52
|
/** x轴虚拟滚动 */
|
|
59
53
|
virtualX: boolean;
|
|
60
|
-
|
|
61
54
|
/** 表格列配置 */
|
|
62
55
|
columns: StkTableColumn<any>[];
|
|
63
|
-
|
|
64
56
|
/** 表格数据源 */
|
|
65
57
|
dataSource: any[];
|
|
66
|
-
|
|
67
58
|
/** 行唯一键 */
|
|
68
59
|
rowKey: UniqKey;
|
|
69
|
-
|
|
70
60
|
/** 列唯一键 */
|
|
71
61
|
colKey: UniqKey;
|
|
72
|
-
|
|
73
62
|
/** 空值展示文字 */
|
|
74
63
|
emptyCellText: string;
|
|
75
|
-
|
|
76
64
|
/** 暂无数据兜底高度是否撑满 */
|
|
77
65
|
noDataFull: boolean;
|
|
78
|
-
|
|
79
66
|
/** 是否展示暂无数据 */
|
|
80
67
|
showNoData: boolean;
|
|
81
|
-
|
|
82
68
|
/** 是否服务端排序,true则不排序数据 */
|
|
83
69
|
sortRemote: boolean;
|
|
84
|
-
|
|
85
70
|
/** 表头是否溢出展示... */
|
|
86
71
|
showHeaderOverflow: boolean;
|
|
87
|
-
|
|
88
72
|
/** 表体溢出是否展示... */
|
|
89
73
|
showOverflow: boolean;
|
|
90
|
-
|
|
91
74
|
/** 是否增加行hover class */
|
|
92
75
|
showTrHoverClass: boolean;
|
|
93
|
-
|
|
94
76
|
/** 表头是否可拖动 */
|
|
95
77
|
headerDrag: boolean;
|
|
96
|
-
|
|
97
78
|
/**
|
|
98
79
|
* 给行附加className<br>
|
|
99
80
|
* FIXME: 是否需要优化,因为不传此prop会使表格行一直执行空函数,是否有影响
|
|
100
81
|
*/
|
|
101
82
|
rowClassName: (row: any, i: number) => string;
|
|
102
|
-
|
|
103
83
|
/**
|
|
104
84
|
* 列宽是否可拖动<br>
|
|
105
85
|
* **不要设置**列minWidth,**必须**设置width<br>
|
|
106
86
|
* 列宽拖动时,每一列都必须要有width,且minWidth/maxWidth不生效。table width会变为"fit-content"。
|
|
107
87
|
*/
|
|
108
88
|
colResizable: boolean;
|
|
109
|
-
|
|
110
89
|
/** 可拖动至最小的列宽 */
|
|
111
90
|
colMinWidth: number;
|
|
112
|
-
|
|
113
91
|
/**
|
|
114
92
|
* 单元格分割线。
|
|
115
93
|
* 默认横竖都有
|
|
@@ -118,7 +96,6 @@ export type StkProps = Partial<{
|
|
|
118
96
|
* "body-v" - 仅表体展示竖线
|
|
119
97
|
*/
|
|
120
98
|
bordered: boolean | 'h' | 'v' | 'body-v';
|
|
121
|
-
|
|
122
99
|
/** 自动重新计算虚拟滚动高度宽度。默认true */
|
|
123
100
|
autoResize: boolean;
|
|
124
101
|
}>;
|
|
@@ -126,7 +103,7 @@ export type StkProps = Partial<{
|
|
|
126
103
|
|
|
127
104
|
### StkTableColumn
|
|
128
105
|
``` ts
|
|
129
|
-
type Sorter = boolean |
|
|
106
|
+
type Sorter<T> = boolean | ((data: T[], option: { order: Order; column: any }) => T[]);
|
|
130
107
|
/** 表格列配置 */
|
|
131
108
|
export type StkTableColumn<T extends Record<string, any>> = {
|
|
132
109
|
/** 取值id */
|
|
@@ -138,7 +115,7 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
138
115
|
/** 表头内容对齐方式 */
|
|
139
116
|
headerAlign?: 'right' | 'left' | 'center';
|
|
140
117
|
/** 筛选 */
|
|
141
|
-
sorter?: Sorter
|
|
118
|
+
sorter?: Sorter<T>;
|
|
142
119
|
/** 列宽。横向虚拟滚动时必须设置。 */
|
|
143
120
|
width?: string;
|
|
144
121
|
/** 最小列宽。非x虚拟滚动生效。 */
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { SortOption, StkTableColumn } from './types/index';
|
|
2
|
-
/**
|
|
3
|
-
* 初始化虚拟滚动参数
|
|
4
|
-
* @param {number} [height] 虚拟滚动的高度
|
|
5
|
-
*/
|
|
6
|
-
declare function initVirtualScroll(height?: number): void;
|
|
7
2
|
/**
|
|
8
3
|
* 选中一行,
|
|
9
4
|
* @param {string} rowKey
|
|
@@ -44,6 +39,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
44
39
|
theme: "light" | "dark";
|
|
45
40
|
virtual: boolean;
|
|
46
41
|
virtualX: boolean;
|
|
42
|
+
/** 排序切换顺序 */
|
|
47
43
|
columns: StkTableColumn<any>[];
|
|
48
44
|
dataSource: any[];
|
|
49
45
|
rowKey: import("./types/index").UniqKey;
|
|
@@ -88,7 +84,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
88
84
|
bordered: boolean;
|
|
89
85
|
autoResize: boolean;
|
|
90
86
|
}>, {
|
|
91
|
-
initVirtualScroll:
|
|
87
|
+
initVirtualScroll: (height?: number | undefined) => void;
|
|
92
88
|
initVirtualScrollX: () => void;
|
|
93
89
|
initVirtualScrollY: (height?: number | undefined) => void;
|
|
94
90
|
setCurrentRow: typeof setCurrentRow;
|
|
@@ -122,6 +118,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
122
118
|
theme: "light" | "dark";
|
|
123
119
|
virtual: boolean;
|
|
124
120
|
virtualX: boolean;
|
|
121
|
+
/** 排序切换顺序 */
|
|
125
122
|
columns: StkTableColumn<any>[];
|
|
126
123
|
dataSource: any[];
|
|
127
124
|
rowKey: import("./types/index").UniqKey;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Component, VNode } from 'vue';
|
|
2
2
|
/** 排序方式,asc-正序,desc-倒序,null-默认顺序 */
|
|
3
3
|
export type Order = null | 'asc' | 'desc';
|
|
4
|
-
type Sorter = boolean | ((data:
|
|
4
|
+
type Sorter<T> = boolean | ((data: T[], option: {
|
|
5
5
|
order: Order;
|
|
6
6
|
column: any;
|
|
7
|
-
}) =>
|
|
7
|
+
}) => T[]);
|
|
8
8
|
export type CustomCellFunc<T extends Record<string, any>> = (props: {
|
|
9
9
|
row: T;
|
|
10
10
|
col: StkTableColumn<T>;
|
|
@@ -24,7 +24,7 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
24
24
|
/** 表头内容对齐方式 */
|
|
25
25
|
headerAlign?: 'right' | 'left' | 'center';
|
|
26
26
|
/** 筛选 */
|
|
27
|
-
sorter?: Sorter
|
|
27
|
+
sorter?: Sorter<T>;
|
|
28
28
|
/** 列宽。横向虚拟滚动时必须设置。 */
|
|
29
29
|
width?: string;
|
|
30
30
|
/** 最小列宽。非x虚拟滚动生效。 */
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
3
|
+
type Options = {
|
|
4
|
+
scrollTo: (x: number | null, y: number | null) => void;
|
|
5
|
+
virtualScroll: Ref<VirtualScrollStore>;
|
|
6
|
+
virtualScrollX: Ref<VirtualScrollXStore>;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* 按下键盘箭头滚动。只有悬浮在表体上才能生效键盘。
|
|
10
|
+
*
|
|
11
|
+
* 在低版本浏览器中,虚拟滚动时,使用键盘滚动,等选中的行消失在视口外时,滚动会失效。
|
|
12
|
+
*/
|
|
13
|
+
export declare function useKeyboardArrowScroll(targetElement: Ref<HTMLElement | undefined>, { scrollTo, virtualScroll, virtualScrollX }: Options): void;
|
|
14
|
+
export {};
|
|
@@ -6,6 +6,37 @@ type Option = {
|
|
|
6
6
|
dataSourceCopy: ShallowRef<any[]>;
|
|
7
7
|
tableHeaderLast: Ref<StkTableColumn<any>[]>;
|
|
8
8
|
};
|
|
9
|
+
/** 暂存纵向虚拟滚动的数据 */
|
|
10
|
+
export type VirtualScrollStore = {
|
|
11
|
+
/** 容器高度 */
|
|
12
|
+
containerHeight: number;
|
|
13
|
+
/** 数组开始位置 */
|
|
14
|
+
startIndex: number;
|
|
15
|
+
/** 行高 */
|
|
16
|
+
rowHeight: number;
|
|
17
|
+
/** 表格定位上边距 */
|
|
18
|
+
offsetTop: number;
|
|
19
|
+
/** 纵向滚动条位置,用于判断是横向滚动还是纵向 */
|
|
20
|
+
scrollTop: number;
|
|
21
|
+
};
|
|
22
|
+
/** 暂存横向虚拟滚动的数据 */
|
|
23
|
+
export type VirtualScrollXStore = {
|
|
24
|
+
/** 容器宽度 */
|
|
25
|
+
containerWidth: number;
|
|
26
|
+
/** 开始位置 */
|
|
27
|
+
startIndex: number;
|
|
28
|
+
/** 结束始位置 */
|
|
29
|
+
endIndex: number;
|
|
30
|
+
/** 表格定位左边距 */
|
|
31
|
+
offsetLeft: number;
|
|
32
|
+
/** 横向滚动位置,用于判断是横向滚动还是纵向 */
|
|
33
|
+
scrollLeft: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* 虚拟滚动
|
|
37
|
+
* @param param0
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
9
40
|
export declare function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLast }: Option): {
|
|
10
41
|
virtualScroll: Ref<{
|
|
11
42
|
containerHeight: number;
|
|
@@ -27,6 +58,7 @@ export declare function useVirtualScroll({ tableContainer, props, dataSourceCopy
|
|
|
27
58
|
virtualX_on: import("vue").ComputedRef<any>;
|
|
28
59
|
virtualX_columnPart: import("vue").ComputedRef<StkTableColumn<any>[]>;
|
|
29
60
|
virtualX_offsetRight: import("vue").ComputedRef<number>;
|
|
61
|
+
initVirtualScroll: (height?: number) => void;
|
|
30
62
|
initVirtualScrollY: (height?: number) => void;
|
|
31
63
|
initVirtualScrollX: () => void;
|
|
32
64
|
updateVirtualScrollY: (sTop?: number) => void;
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -280,6 +280,52 @@ function useHighlight({ props, tableContainer, rowKeyGen }) {
|
|
|
280
280
|
setHighlightDimCell
|
|
281
281
|
};
|
|
282
282
|
}
|
|
283
|
+
const ARROW_CODES = ["ArrowUp", "ArrowRight", "ArrowDown", "ArrowLeft"];
|
|
284
|
+
function useKeyboardArrowScroll(targetElement, { scrollTo, virtualScroll, virtualScrollX }) {
|
|
285
|
+
let isMouseOver = false;
|
|
286
|
+
onMounted(() => {
|
|
287
|
+
var _a, _b, _c;
|
|
288
|
+
window.addEventListener("keydown", handleKeydown);
|
|
289
|
+
(_a = targetElement.value) == null ? void 0 : _a.addEventListener("mouseenter", handleMouseEnter);
|
|
290
|
+
(_b = targetElement.value) == null ? void 0 : _b.addEventListener("mouseleave", handleMouseLeave);
|
|
291
|
+
(_c = targetElement.value) == null ? void 0 : _c.addEventListener("mousedown", handleMouseDown);
|
|
292
|
+
});
|
|
293
|
+
onBeforeUnmount(() => {
|
|
294
|
+
var _a, _b, _c;
|
|
295
|
+
window.removeEventListener("keydown", handleKeydown);
|
|
296
|
+
(_a = targetElement.value) == null ? void 0 : _a.removeEventListener("mouseenter", handleMouseEnter);
|
|
297
|
+
(_b = targetElement.value) == null ? void 0 : _b.removeEventListener("mouseleave", handleMouseLeave);
|
|
298
|
+
(_c = targetElement.value) == null ? void 0 : _c.removeEventListener("mousedown", handleMouseDown);
|
|
299
|
+
});
|
|
300
|
+
function handleKeydown(e) {
|
|
301
|
+
if (!ARROW_CODES.includes(e.code))
|
|
302
|
+
return;
|
|
303
|
+
if (!isMouseOver)
|
|
304
|
+
return;
|
|
305
|
+
e.preventDefault();
|
|
306
|
+
const { scrollTop, rowHeight } = virtualScroll.value;
|
|
307
|
+
const { scrollLeft } = virtualScrollX.value;
|
|
308
|
+
if (e.code === ARROW_CODES[0]) {
|
|
309
|
+
scrollTo(scrollTop - rowHeight, null);
|
|
310
|
+
} else if (e.code === ARROW_CODES[1]) {
|
|
311
|
+
scrollTo(null, scrollLeft + rowHeight);
|
|
312
|
+
} else if (e.code === ARROW_CODES[2]) {
|
|
313
|
+
scrollTo(scrollTop + rowHeight, null);
|
|
314
|
+
} else if (e.code === ARROW_CODES[3]) {
|
|
315
|
+
scrollTo(null, scrollLeft - rowHeight);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function handleMouseEnter() {
|
|
319
|
+
isMouseOver = true;
|
|
320
|
+
}
|
|
321
|
+
function handleMouseLeave() {
|
|
322
|
+
isMouseOver = false;
|
|
323
|
+
}
|
|
324
|
+
function handleMouseDown() {
|
|
325
|
+
if (!isMouseOver)
|
|
326
|
+
isMouseOver = true;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
283
329
|
function useThDrag({ emit }) {
|
|
284
330
|
let dragStartKey = void 0;
|
|
285
331
|
function onThDragStart(e) {
|
|
@@ -311,12 +357,9 @@ function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLa
|
|
|
311
357
|
const virtualScroll = ref({
|
|
312
358
|
containerHeight: 0,
|
|
313
359
|
startIndex: 0,
|
|
314
|
-
// 数组开始位置
|
|
315
360
|
rowHeight: 28,
|
|
316
361
|
offsetTop: 0,
|
|
317
|
-
// 表格定位上边距
|
|
318
362
|
scrollTop: 0
|
|
319
|
-
// 纵向滚动条位置,用于判断是横向滚动还是纵向
|
|
320
363
|
});
|
|
321
364
|
const virtualScrollX = ref({
|
|
322
365
|
containerWidth: 0,
|
|
@@ -324,7 +367,6 @@ function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLa
|
|
|
324
367
|
endIndex: 0,
|
|
325
368
|
offsetLeft: 0,
|
|
326
369
|
scrollLeft: 0
|
|
327
|
-
// 横向滚动位置,用于判断是横向滚动还是纵向
|
|
328
370
|
});
|
|
329
371
|
const virtual_on = computed(() => {
|
|
330
372
|
return props.virtual && dataSourceCopy.value.length > virtual_pageSize.value * 2;
|
|
@@ -375,11 +417,15 @@ function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLa
|
|
|
375
417
|
return width;
|
|
376
418
|
});
|
|
377
419
|
function initVirtualScrollY(height) {
|
|
378
|
-
var _a, _b;
|
|
379
420
|
if (!virtual_on.value)
|
|
380
421
|
return;
|
|
381
|
-
|
|
382
|
-
|
|
422
|
+
const { offsetHeight, scrollTop } = tableContainer.value || {};
|
|
423
|
+
if (typeof height === "number") {
|
|
424
|
+
virtualScroll.value.containerHeight = height;
|
|
425
|
+
} else {
|
|
426
|
+
virtualScroll.value.containerHeight = offsetHeight || Default_Table_Height;
|
|
427
|
+
}
|
|
428
|
+
updateVirtualScrollY(scrollTop);
|
|
383
429
|
}
|
|
384
430
|
function initVirtualScrollX() {
|
|
385
431
|
if (!props.virtualX)
|
|
@@ -388,6 +434,10 @@ function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLa
|
|
|
388
434
|
virtualScrollX.value.containerWidth = offsetWidth || Default_Table_Width;
|
|
389
435
|
updateVirtualScrollX(scrollLeft);
|
|
390
436
|
}
|
|
437
|
+
function initVirtualScroll(height) {
|
|
438
|
+
initVirtualScrollY(height);
|
|
439
|
+
initVirtualScrollX();
|
|
440
|
+
}
|
|
391
441
|
function updateVirtualScrollY(sTop = 0) {
|
|
392
442
|
const { rowHeight } = virtualScroll.value;
|
|
393
443
|
const startIndex = Math.floor(sTop / rowHeight);
|
|
@@ -438,6 +488,7 @@ function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLa
|
|
|
438
488
|
virtualX_on,
|
|
439
489
|
virtualX_columnPart,
|
|
440
490
|
virtualX_offsetRight,
|
|
491
|
+
initVirtualScroll,
|
|
441
492
|
initVirtualScrollY,
|
|
442
493
|
initVirtualScrollX,
|
|
443
494
|
updateVirtualScrollY,
|
|
@@ -697,6 +748,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
697
748
|
virtualX_on,
|
|
698
749
|
virtualX_columnPart,
|
|
699
750
|
virtualX_offsetRight,
|
|
751
|
+
initVirtualScroll,
|
|
700
752
|
initVirtualScrollY,
|
|
701
753
|
initVirtualScrollX,
|
|
702
754
|
updateVirtualScrollY,
|
|
@@ -706,6 +758,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
706
758
|
if (props.autoResize) {
|
|
707
759
|
useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs: 500 });
|
|
708
760
|
}
|
|
761
|
+
useKeyboardArrowScroll(tableContainer, {
|
|
762
|
+
scrollTo,
|
|
763
|
+
virtualScroll,
|
|
764
|
+
virtualScrollX
|
|
765
|
+
});
|
|
709
766
|
watch(
|
|
710
767
|
() => props.columns,
|
|
711
768
|
() => {
|
|
@@ -740,10 +797,6 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
740
797
|
onMounted(() => {
|
|
741
798
|
initVirtualScroll();
|
|
742
799
|
});
|
|
743
|
-
function initVirtualScroll(height) {
|
|
744
|
-
initVirtualScrollY(height);
|
|
745
|
-
initVirtualScrollX();
|
|
746
|
-
}
|
|
747
800
|
function getFixedStyle(tagType, col) {
|
|
748
801
|
const style = {};
|
|
749
802
|
if (Is_Legacy_Mode) {
|
package/lib/style.css
CHANGED
|
@@ -1,255 +1,257 @@
|
|
|
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
|
-
.stk-table.headless
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
.stk-table.is-col-resizing th
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
.stk-table.border-h
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
.stk-table.border-v
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
.stk-table.border .stk-table-main th,
|
|
60
|
-
.stk-table.border .stk-table-main td
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
.stk-table.border .stk-table-main thead tr:first-child th
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
.stk-table.border .stk-table-main thead tr:first-child th:first-child
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
.stk-table.border .stk-table-main thead tr th:first-child
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
.stk-table.border .stk-table-main tbody td:first-child
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
.stk-table.border.virtual-x .stk-table-main thead tr:first-child .virtual-x-left + th
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
.stk-table.border.virtual-x .stk-table-main tr .virtual-x-left + th
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
.stk-table.border-body-v .stk-table-main tbody
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
.stk-table .column-resize-indicator
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
.stk-table .stk-table-main
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
.stk-table .stk-table-main
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
1
|
+
|
|
2
|
+
.stk-table{
|
|
3
|
+
--row-height:28px;
|
|
4
|
+
--cell-padding-x:8px;
|
|
5
|
+
--resize-handle-width:4px;
|
|
6
|
+
--border-color:#e8eaec;
|
|
7
|
+
--border-width:1px;
|
|
8
|
+
--td-bgc:#fff;
|
|
9
|
+
--th-bgc:#f8f8f9;
|
|
10
|
+
--tr-active-bgc:rgb(230, 247, 255);
|
|
11
|
+
--tr-hover-bgc:rgba(230, 247, 255, 0.7);
|
|
12
|
+
--bg-border-top:linear-gradient(180deg, var(--border-color) var(--border-width), transparent var(--border-width));
|
|
13
|
+
--bg-border-right:linear-gradient(270deg, var(--border-color) var(--border-width), transparent var(--border-width));
|
|
14
|
+
--bg-border-bottom:linear-gradient(0deg, var(--border-color) var(--border-width), transparent var(--border-width));
|
|
15
|
+
--bg-border-left:linear-gradient(90deg, var(--border-color) var(--border-width), transparent var(--border-width));
|
|
16
|
+
--highlight-color:#71a2fd;
|
|
17
|
+
|
|
18
|
+
--sort-arrow-color:#5d5f69;
|
|
19
|
+
--sort-arrow-hover-color:#8f90b5;
|
|
20
|
+
--sort-arrow-active-color:#1b63d9;
|
|
21
|
+
--sort-arrow-active-sub-color:#cbcbe1;
|
|
22
|
+
--col-resize-indicator-color:#cbcbe1;
|
|
23
|
+
|
|
24
|
+
position:relative;
|
|
25
|
+
overflow:auto;
|
|
26
|
+
display:flex;
|
|
27
|
+
flex-direction:column;
|
|
28
|
+
}
|
|
29
|
+
.stk-table.dark{
|
|
30
|
+
--th-bgc:#181c21;
|
|
31
|
+
--td-bgc:#181c21;
|
|
32
|
+
--border-color:#26292e;
|
|
33
|
+
--tr-active-bgc:#283f63;
|
|
34
|
+
--tr-hover-bgc:#1a2b46;
|
|
35
|
+
--table-bgc:#181c21;
|
|
36
|
+
--highlight-color:#1e4c99;
|
|
37
|
+
|
|
38
|
+
--sort-arrow-color:#5d6064;
|
|
39
|
+
--sort-arrow-hover-color:#727782;
|
|
40
|
+
--sort-arrow-active-color:#d0d1d2;
|
|
41
|
+
--sort-arrow-active-sub-color:#5d6064;
|
|
42
|
+
|
|
43
|
+
--col-resize-indicator-color:#5d6064;
|
|
44
|
+
color:#d0d1d2;
|
|
45
|
+
}
|
|
46
|
+
.stk-table.headless{
|
|
47
|
+
border-top:1px solid var(--border-color);
|
|
48
|
+
}
|
|
49
|
+
.stk-table.is-col-resizing th{
|
|
50
|
+
pointer-events:none;
|
|
51
|
+
}
|
|
52
|
+
.stk-table.border-h{
|
|
53
|
+
--bg-border-right:linear-gradient(transparent, transparent);
|
|
54
|
+
--bg-border-left:linear-gradient(transparent, transparent);
|
|
55
|
+
}
|
|
56
|
+
.stk-table.border-v{
|
|
57
|
+
--bg-border-bottom:linear-gradient(transparent, transparent);
|
|
58
|
+
}
|
|
59
|
+
.stk-table.border .stk-table-main th,
|
|
60
|
+
.stk-table.border .stk-table-main td{
|
|
61
|
+
background-image:var(--bg-border-right), var(--bg-border-bottom);
|
|
62
|
+
}
|
|
63
|
+
.stk-table.border .stk-table-main thead tr:first-child th{
|
|
64
|
+
background-image:var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
|
|
65
|
+
}
|
|
66
|
+
.stk-table.border .stk-table-main thead tr:first-child th:first-child{
|
|
67
|
+
background-image:var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
|
|
68
|
+
}
|
|
69
|
+
.stk-table.border .stk-table-main thead tr th:first-child{
|
|
70
|
+
background-image:var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
|
|
71
|
+
}
|
|
72
|
+
.stk-table.border .stk-table-main tbody td:first-child{
|
|
73
|
+
background-image:var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
|
|
74
|
+
}
|
|
75
|
+
.stk-table.border.virtual-x .stk-table-main thead tr:first-child .virtual-x-left + th{
|
|
76
|
+
background-image:var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
|
|
77
|
+
}
|
|
78
|
+
.stk-table.border.virtual-x .stk-table-main tr .virtual-x-left + th{
|
|
79
|
+
background-image:var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
|
|
80
|
+
}
|
|
81
|
+
.stk-table.border-body-v .stk-table-main tbody{
|
|
82
|
+
--bg-border-bottom:linear-gradient(transparent, transparent);
|
|
83
|
+
}
|
|
84
|
+
.stk-table .column-resize-indicator{
|
|
85
|
+
width:0;
|
|
86
|
+
height:100%;
|
|
87
|
+
border-left:1px dashed var(--col-resize-indicator-color);
|
|
88
|
+
position:absolute;
|
|
89
|
+
z-index:10;
|
|
90
|
+
display:none;
|
|
91
|
+
pointer-events:none;
|
|
92
|
+
}
|
|
93
|
+
.stk-table .stk-table-main{
|
|
94
|
+
border-spacing:0;
|
|
95
|
+
border-collapse:separate;
|
|
96
|
+
width:-moz-fit-content;
|
|
97
|
+
width:fit-content;
|
|
98
|
+
min-width:100%;
|
|
99
|
+
}
|
|
100
|
+
.stk-table .stk-table-main.fixed-mode{
|
|
101
|
+
table-layout:fixed;
|
|
102
|
+
}
|
|
103
|
+
.stk-table .stk-table-main th,
|
|
104
|
+
.stk-table .stk-table-main td{
|
|
105
|
+
z-index:1;
|
|
106
|
+
height:var(--row-height);
|
|
107
|
+
font-size:14px;
|
|
108
|
+
box-sizing:border-box;
|
|
109
|
+
padding:0 var(--cell-padding-x);
|
|
110
|
+
}
|
|
111
|
+
.stk-table .stk-table-main thead tr:first-child th{
|
|
112
|
+
position:sticky;
|
|
113
|
+
top:0;
|
|
114
|
+
}
|
|
115
|
+
.stk-table .stk-table-main thead tr th{
|
|
116
|
+
background-color:var(--th-bgc);
|
|
117
|
+
}
|
|
118
|
+
.stk-table .stk-table-main thead tr th.sortable{
|
|
119
|
+
cursor:pointer;
|
|
120
|
+
}
|
|
121
|
+
.stk-table .stk-table-main thead tr th.text-overflow .table-header-cell-wrapper{
|
|
122
|
+
white-space:nowrap;
|
|
123
|
+
overflow:hidden;
|
|
124
|
+
}
|
|
125
|
+
.stk-table .stk-table-main thead tr th.text-overflow .table-header-cell-wrapper .table-header-title{
|
|
126
|
+
text-overflow:ellipsis;
|
|
127
|
+
overflow:hidden;
|
|
128
|
+
}
|
|
129
|
+
.stk-table .stk-table-main thead tr th:not(.sorter-desc):not(.sorter-asc):hover .table-header-cell-wrapper .table-header-sorter #arrow-up{
|
|
130
|
+
fill:var(--sort-arrow-hover-color);
|
|
131
|
+
}
|
|
132
|
+
.stk-table .stk-table-main thead tr th:not(.sorter-desc):not(.sorter-asc):hover .table-header-cell-wrapper .table-header-sorter #arrow-down{
|
|
133
|
+
fill:var(--sort-arrow-hover-color);
|
|
134
|
+
}
|
|
135
|
+
.stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter{
|
|
136
|
+
display:inline;
|
|
137
|
+
display:initial;
|
|
138
|
+
}
|
|
139
|
+
.stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter #arrow-up{
|
|
140
|
+
fill:var(--sort-arrow-active-sub-color);
|
|
139
141
|
}
|
|
140
|
-
.stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter #arrow-down
|
|
141
|
-
|
|
142
|
+
.stk-table .stk-table-main thead tr th.sorter-desc .table-header-cell-wrapper .table-header-sorter #arrow-down{
|
|
143
|
+
fill:var(--sort-arrow-active-color);
|
|
142
144
|
}
|
|
143
|
-
.stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter
|
|
144
|
-
|
|
145
|
+
.stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter{
|
|
146
|
+
display:inline;
|
|
147
|
+
display:initial;
|
|
145
148
|
}
|
|
146
|
-
.stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter #arrow-up
|
|
147
|
-
|
|
149
|
+
.stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter #arrow-up{
|
|
150
|
+
fill:var(--sort-arrow-active-color);
|
|
148
151
|
}
|
|
149
|
-
.stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter #arrow-down
|
|
150
|
-
|
|
152
|
+
.stk-table .stk-table-main thead tr th.sorter-asc .table-header-cell-wrapper .table-header-sorter #arrow-down{
|
|
153
|
+
fill:var(--sort-arrow-active-sub-color);
|
|
151
154
|
}
|
|
152
|
-
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper{
|
|
156
|
+
max-width:100%;
|
|
157
|
+
display:inline-flex;
|
|
158
|
+
align-items:center;
|
|
156
159
|
}
|
|
157
|
-
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-title
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-title{
|
|
161
|
+
overflow:hidden;
|
|
162
|
+
align-self:flex-start;
|
|
160
163
|
}
|
|
161
|
-
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter{
|
|
165
|
+
flex-shrink:0;
|
|
166
|
+
margin-left:4px;
|
|
167
|
+
width:16px;
|
|
168
|
+
height:16px;
|
|
169
|
+
display:none;
|
|
170
|
+
}
|
|
171
|
+
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter #arrow-up,
|
|
172
|
+
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter #arrow-down{
|
|
173
|
+
fill:var(--sort-arrow-color);
|
|
174
|
+
}
|
|
175
|
+
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer{
|
|
176
|
+
position:absolute;
|
|
177
|
+
top:0;
|
|
178
|
+
bottom:0;
|
|
179
|
+
cursor:col-resize;
|
|
180
|
+
width:var(--resize-handle-width);
|
|
181
|
+
}
|
|
182
|
+
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer.left{
|
|
183
|
+
left:0;
|
|
184
|
+
}
|
|
185
|
+
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer.right{
|
|
186
|
+
right:0;
|
|
187
|
+
}
|
|
188
|
+
.stk-table .stk-table-main tbody{
|
|
189
|
+
@keyframes dim{
|
|
190
|
+
from{
|
|
191
|
+
background-color:var(--highlight-color);
|
|
167
192
|
}
|
|
168
|
-
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter #arrow-up,
|
|
169
|
-
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-sorter #arrow-down {
|
|
170
|
-
fill: var(--sort-arrow-color);
|
|
171
193
|
}
|
|
172
|
-
.stk-table .stk-table-main thead tr th .table-header-cell-wrapper .table-header-resizer {
|
|
173
|
-
position: absolute;
|
|
174
|
-
top: 0;
|
|
175
|
-
bottom: 0;
|
|
176
|
-
cursor: col-resize;
|
|
177
|
-
width: var(--resize-handle-width);
|
|
178
194
|
}
|
|
179
|
-
.stk-table .stk-table-main
|
|
180
|
-
|
|
195
|
+
.stk-table .stk-table-main tbody tr{
|
|
196
|
+
background-color:var(--td-bgc);
|
|
197
|
+
}
|
|
198
|
+
.stk-table .stk-table-main tbody tr.highlight-row{
|
|
199
|
+
animation:dim 2s linear;
|
|
200
|
+
}
|
|
201
|
+
.stk-table .stk-table-main tbody tr.hover,
|
|
202
|
+
.stk-table .stk-table-main tbody tr:hover{
|
|
203
|
+
background-color:var(--tr-hover-bgc);
|
|
181
204
|
}
|
|
182
|
-
.stk-table .stk-table-main
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
.stk-table .stk-table-main tbody {
|
|
186
|
-
/**高亮渐暗 */
|
|
205
|
+
.stk-table .stk-table-main tbody tr.active{
|
|
206
|
+
background-color:var(--tr-active-bgc);
|
|
187
207
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
background-color: var(--highlight-color);
|
|
208
|
+
.stk-table .stk-table-main tbody tr td.fixed-cell{
|
|
209
|
+
background-color:inherit;
|
|
191
210
|
}
|
|
211
|
+
.stk-table .stk-table-main tbody tr td.highlight-cell{
|
|
212
|
+
animation:dim 2s linear;
|
|
192
213
|
}
|
|
193
|
-
.stk-table .stk-table-main tbody tr {
|
|
194
|
-
|
|
214
|
+
.stk-table .stk-table-main tbody tr td.text-overflow .table-cell-wrapper{
|
|
215
|
+
white-space:nowrap;
|
|
216
|
+
overflow:hidden;
|
|
217
|
+
text-overflow:ellipsis;
|
|
195
218
|
}
|
|
196
|
-
.stk-table .stk-table-
|
|
197
|
-
|
|
219
|
+
.stk-table .stk-table-no-data{
|
|
220
|
+
background-color:var(--table-bgc);
|
|
221
|
+
line-height:var(--row-height);
|
|
222
|
+
text-align:center;
|
|
223
|
+
font-size:14px;
|
|
224
|
+
position:sticky;
|
|
225
|
+
left:0px;
|
|
226
|
+
border-left:var(--border-width) solid var(--border-color);
|
|
227
|
+
border-right:var(--border-width) solid var(--border-color);
|
|
228
|
+
border-bottom:var(--border-width) solid var(--border-color);
|
|
229
|
+
display:flex;
|
|
230
|
+
flex-direction:column;
|
|
231
|
+
align-items:center;
|
|
232
|
+
justify-content:center;
|
|
198
233
|
}
|
|
199
|
-
.stk-table .stk-table-
|
|
200
|
-
|
|
201
|
-
background-color: var(--tr-hover-bgc);
|
|
234
|
+
.stk-table .stk-table-no-data.no-data-full{
|
|
235
|
+
flex:1;
|
|
202
236
|
}
|
|
203
|
-
.stk-table .stk-table-main
|
|
204
|
-
|
|
237
|
+
.stk-table.virtual .stk-table-main thead tr th .table-header-cell-wrapper{
|
|
238
|
+
overflow:hidden;
|
|
239
|
+
max-height:var(--row-height);
|
|
205
240
|
}
|
|
206
|
-
.stk-table .stk-table-main tbody
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
.stk-table .stk-table-main tbody tr td.highlight-cell {
|
|
210
|
-
animation: dim 2s linear;
|
|
211
|
-
}
|
|
212
|
-
.stk-table .stk-table-main tbody tr td.text-overflow .table-cell-wrapper {
|
|
213
|
-
white-space: nowrap;
|
|
214
|
-
overflow: hidden;
|
|
215
|
-
text-overflow: ellipsis;
|
|
216
|
-
}
|
|
217
|
-
.stk-table .stk-table-no-data {
|
|
218
|
-
background-color: var(--table-bgc);
|
|
219
|
-
line-height: var(--row-height);
|
|
220
|
-
text-align: center;
|
|
221
|
-
font-size: 14px;
|
|
222
|
-
position: sticky;
|
|
223
|
-
left: 0px;
|
|
224
|
-
border-left: var(--border-width) solid var(--border-color);
|
|
225
|
-
border-right: var(--border-width) solid var(--border-color);
|
|
226
|
-
border-bottom: var(--border-width) solid var(--border-color);
|
|
227
|
-
display: flex;
|
|
228
|
-
flex-direction: column;
|
|
229
|
-
align-items: center;
|
|
230
|
-
justify-content: center;
|
|
231
|
-
}
|
|
232
|
-
.stk-table .stk-table-no-data.no-data-full {
|
|
233
|
-
flex: 1;
|
|
234
|
-
}
|
|
235
|
-
.stk-table.virtual .stk-table-main thead tr th .table-header-cell-wrapper {
|
|
236
|
-
overflow: hidden;
|
|
237
|
-
max-height: var(--row-height);
|
|
238
|
-
}
|
|
239
|
-
.stk-table.virtual .stk-table-main tbody {
|
|
240
|
-
position: relative;
|
|
241
|
-
}
|
|
242
|
-
.stk-table.virtual .stk-table-main tbody tr.padding-top-tr td {
|
|
243
|
-
height: 0;
|
|
244
|
-
}
|
|
245
|
-
.stk-table.virtual .stk-table-main tbody tr td {
|
|
246
|
-
height: var(--row-height);
|
|
247
|
-
line-height: 1;
|
|
248
|
-
}
|
|
249
|
-
.stk-table.virtual .stk-table-main tbody tr td .table-cell-wrapper {
|
|
250
|
-
max-height: var(--row-height);
|
|
251
|
-
overflow: hidden;
|
|
252
|
-
}
|
|
253
|
-
.stk-table.virtual-x .stk-table-main .virtual-x-left {
|
|
254
|
-
padding: 0;
|
|
241
|
+
.stk-table.virtual .stk-table-main tbody{
|
|
242
|
+
position:relative;
|
|
255
243
|
}
|
|
244
|
+
.stk-table.virtual .stk-table-main tbody tr.padding-top-tr td{
|
|
245
|
+
height:0;
|
|
246
|
+
}
|
|
247
|
+
.stk-table.virtual .stk-table-main tbody tr td{
|
|
248
|
+
height:var(--row-height);
|
|
249
|
+
line-height:1;
|
|
250
|
+
}
|
|
251
|
+
.stk-table.virtual .stk-table-main tbody tr td .table-cell-wrapper{
|
|
252
|
+
max-height:var(--row-height);
|
|
253
|
+
overflow:hidden;
|
|
254
|
+
}
|
|
255
|
+
.stk-table.virtual-x .stk-table-main .virtual-x-left{
|
|
256
|
+
padding:0;
|
|
257
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stk-table-vue",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.7",
|
|
4
4
|
"description": "simple realtime virtual table for vue3",
|
|
5
5
|
"main": "./lib/stk-table-vue.js",
|
|
6
6
|
"types": "./lib/StkTable/index.d.ts",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"eslint-plugin-prettier": "^5.0.1",
|
|
44
44
|
"eslint-plugin-vue": "^9.19.2",
|
|
45
45
|
"happy-dom": "^12.10.3",
|
|
46
|
-
"
|
|
46
|
+
"postcss-discard-comments": "^6.0.1",
|
|
47
|
+
"postcss-preset-env": "^9.3.0",
|
|
47
48
|
"prettier": "^3.1.1",
|
|
48
49
|
"pug": "^3.0.2",
|
|
49
50
|
"typescript": "^5.3.3",
|
|
@@ -51,8 +52,7 @@
|
|
|
51
52
|
"vite-plugin-dts": "^3.6.4",
|
|
52
53
|
"vitest": "^1.1.0",
|
|
53
54
|
"vue": "^3.3.9",
|
|
54
|
-
"vue-eslint-parser": "^9.3.2"
|
|
55
|
-
"vue-loader": "^17.2.2"
|
|
55
|
+
"vue-eslint-parser": "^9.3.2"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"d3-interpolate": "^3.0.1"
|
|
@@ -201,6 +201,7 @@ import { Order, SortOption, StkProps, StkTableColumn } from './types/index';
|
|
|
201
201
|
import { useAutoResize } from './useAutoResize';
|
|
202
202
|
import { useColResize } from './useColResize';
|
|
203
203
|
import { useHighlight } from './useHighlight';
|
|
204
|
+
import { useKeyboardArrowScroll } from './useKeyboardArrowScroll';
|
|
204
205
|
import { useThDrag } from './useThDrag';
|
|
205
206
|
import { useVirtualScroll } from './useVirtualScroll';
|
|
206
207
|
import { howDeepTheColumn, tableSort } from './utils';
|
|
@@ -335,6 +336,7 @@ const {
|
|
|
335
336
|
virtualX_on,
|
|
336
337
|
virtualX_columnPart,
|
|
337
338
|
virtualX_offsetRight,
|
|
339
|
+
initVirtualScroll,
|
|
338
340
|
initVirtualScrollY,
|
|
339
341
|
initVirtualScrollX,
|
|
340
342
|
updateVirtualScrollY,
|
|
@@ -350,6 +352,13 @@ if (props.autoResize) {
|
|
|
350
352
|
useAutoResize({ tableContainer, initVirtualScroll, scrollTo, props, debounceMs: 500 });
|
|
351
353
|
}
|
|
352
354
|
|
|
355
|
+
/** 键盘箭头滚动 */
|
|
356
|
+
useKeyboardArrowScroll(tableContainer, {
|
|
357
|
+
scrollTo,
|
|
358
|
+
virtualScroll,
|
|
359
|
+
virtualScrollX,
|
|
360
|
+
});
|
|
361
|
+
|
|
353
362
|
watch(
|
|
354
363
|
() => props.columns,
|
|
355
364
|
() => {
|
|
@@ -390,15 +399,6 @@ onMounted(() => {
|
|
|
390
399
|
initVirtualScroll();
|
|
391
400
|
});
|
|
392
401
|
|
|
393
|
-
/**
|
|
394
|
-
* 初始化虚拟滚动参数
|
|
395
|
-
* @param {number} [height] 虚拟滚动的高度
|
|
396
|
-
*/
|
|
397
|
-
function initVirtualScroll(height?: number) {
|
|
398
|
-
initVirtualScrollY(height);
|
|
399
|
-
initVirtualScrollX();
|
|
400
|
-
}
|
|
401
|
-
|
|
402
402
|
/**
|
|
403
403
|
* 固定列的style
|
|
404
404
|
* @param {1|2} tagType 1-th 2-td
|
|
@@ -729,9 +729,9 @@ defineExpose({
|
|
|
729
729
|
});
|
|
730
730
|
</script>
|
|
731
731
|
|
|
732
|
-
<style
|
|
732
|
+
<style type="css">
|
|
733
733
|
.stk-table {
|
|
734
|
-
|
|
734
|
+
/* contain: strict;*/
|
|
735
735
|
--row-height: 28px;
|
|
736
736
|
--cell-padding-x: 8px;
|
|
737
737
|
--resize-handle-width: 4px;
|
|
@@ -767,7 +767,7 @@ defineExpose({
|
|
|
767
767
|
--tr-active-bgc: #283f63;
|
|
768
768
|
--tr-hover-bgc: #1a2b46;
|
|
769
769
|
--table-bgc: #181c21;
|
|
770
|
-
--highlight-color: #1e4c99;
|
|
770
|
+
--highlight-color: #1e4c99; /* 不能用rgba,因为固定列时,会变成半透明*/
|
|
771
771
|
|
|
772
772
|
--sort-arrow-color: #5d6064;
|
|
773
773
|
--sort-arrow-hover-color: #727782;
|
|
@@ -776,19 +776,19 @@ defineExpose({
|
|
|
776
776
|
|
|
777
777
|
--col-resize-indicator-color: #5d6064;
|
|
778
778
|
|
|
779
|
-
|
|
779
|
+
/* background-color: var(--table-bgc); */ /* ⭐这里加background-color会导致表格出滚动白屏*/
|
|
780
780
|
color: #d0d1d2;
|
|
781
781
|
}
|
|
782
782
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
783
|
+
/*.stk-table-fixed-left-col-box-shadow {
|
|
784
|
+
position: sticky;
|
|
785
|
+
left: 0;
|
|
786
|
+
top: 0;
|
|
787
|
+
height: 100%;
|
|
788
|
+
box-shadow: 0 0 10px;
|
|
789
|
+
z-index: 1;
|
|
790
|
+
pointer-events: none;
|
|
791
|
+
}*/
|
|
792
792
|
&.headless {
|
|
793
793
|
border-top: 1px solid var(--border-color);
|
|
794
794
|
}
|
|
@@ -839,7 +839,7 @@ defineExpose({
|
|
|
839
839
|
&.virtual-x {
|
|
840
840
|
.stk-table-main {
|
|
841
841
|
thead tr:first-child .virtual-x-left + th {
|
|
842
|
-
|
|
842
|
+
/* 横向虚拟滚动时,左侧第一个单元格加上border-left*/
|
|
843
843
|
background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
|
|
844
844
|
}
|
|
845
845
|
|
|
@@ -871,8 +871,8 @@ defineExpose({
|
|
|
871
871
|
.stk-table-main {
|
|
872
872
|
border-spacing: 0;
|
|
873
873
|
border-collapse: separate;
|
|
874
|
-
width: fit-content;
|
|
875
|
-
min-width: 100%;
|
|
874
|
+
width: fit-content; /* 用于兼容低版本,低版本width超过100%的时候还是100%,导致sticky错误。*/
|
|
875
|
+
min-width: 100%; /* 用于兼容低版本chrome。低版本min-width 是min-content;*/
|
|
876
876
|
&.fixed-mode {
|
|
877
877
|
table-layout: fixed;
|
|
878
878
|
}
|
|
@@ -945,7 +945,7 @@ defineExpose({
|
|
|
945
945
|
}
|
|
946
946
|
|
|
947
947
|
.table-header-cell-wrapper {
|
|
948
|
-
max-width: 100%;
|
|
948
|
+
max-width: 100%; /*最大宽度不超过列宽*/
|
|
949
949
|
display: inline-flex;
|
|
950
950
|
align-items: center;
|
|
951
951
|
|
|
@@ -995,15 +995,15 @@ defineExpose({
|
|
|
995
995
|
}
|
|
996
996
|
|
|
997
997
|
tr {
|
|
998
|
-
background-color: var(--td-bgc);
|
|
998
|
+
background-color: var(--td-bgc); /* td inherit tr bgc*/
|
|
999
999
|
|
|
1000
1000
|
&.highlight-row {
|
|
1001
1001
|
animation: dim 2s linear;
|
|
1002
1002
|
}
|
|
1003
1003
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1004
|
+
/* &.highlight-row-transition {
|
|
1005
|
+
transition: background-color v-bind(highlightStepDuration) linear;
|
|
1006
|
+
}*/
|
|
1007
1007
|
|
|
1008
1008
|
&.hover,
|
|
1009
1009
|
&:hover {
|
|
@@ -1016,7 +1016,7 @@ defineExpose({
|
|
|
1016
1016
|
|
|
1017
1017
|
td {
|
|
1018
1018
|
&.fixed-cell {
|
|
1019
|
-
background-color: inherit;
|
|
1019
|
+
background-color: inherit; /* 防止横向滚动后透明*/
|
|
1020
1020
|
}
|
|
1021
1021
|
|
|
1022
1022
|
&.highlight-cell {
|
|
@@ -1031,40 +1031,40 @@ defineExpose({
|
|
|
1031
1031
|
}
|
|
1032
1032
|
}
|
|
1033
1033
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1034
|
+
/* &.perch-td {
|
|
1035
|
+
padding: 0;
|
|
1036
|
+
height: 0;
|
|
1037
|
+
&.top {
|
|
1038
|
+
background-image: repeating-linear-gradient(
|
|
1039
|
+
180deg,
|
|
1040
|
+
transparent 0,
|
|
1041
|
+
transparent var(--row-height),
|
|
1042
|
+
var(--border-color) var(--row-height),
|
|
1043
|
+
var(--border-color) calc(var(--row-height) + 1px)
|
|
1044
|
+
),
|
|
1045
|
+
var(--bg-border-right);
|
|
1046
|
+
}
|
|
1047
|
+
&.bottom {
|
|
1048
|
+
background-image: repeating-linear-gradient(
|
|
1049
|
+
0deg,
|
|
1050
|
+
transparent 0,
|
|
1051
|
+
transparent var(--row-height),
|
|
1052
|
+
var(--border-color) var(--row-height),
|
|
1053
|
+
var(--border-color) calc(var(--row-height) + 1px)
|
|
1054
|
+
),
|
|
1055
|
+
var(--bg-border-right);
|
|
1056
|
+
}
|
|
1057
|
+
}*/
|
|
1058
1058
|
}
|
|
1059
1059
|
}
|
|
1060
1060
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1061
|
+
/* 斑马纹
|
|
1062
|
+
tr:nth-child(2n) td {
|
|
1063
|
+
background-color: #fafafc;
|
|
1064
|
+
}
|
|
1065
|
+
tr:hover {
|
|
1066
|
+
background-color: #ebf3ff;
|
|
1067
|
+
}*/
|
|
1068
1068
|
}
|
|
1069
1069
|
}
|
|
1070
1070
|
|
|
@@ -1094,7 +1094,7 @@ defineExpose({
|
|
|
1094
1094
|
thead {
|
|
1095
1095
|
tr {
|
|
1096
1096
|
th {
|
|
1097
|
-
|
|
1097
|
+
/* 为不影响布局,表头行高要定死*/
|
|
1098
1098
|
.table-header-cell-wrapper {
|
|
1099
1099
|
overflow: hidden;
|
|
1100
1100
|
max-height: var(--row-height);
|
|
@@ -3,7 +3,7 @@ import { Component, VNode } from 'vue';
|
|
|
3
3
|
/** 排序方式,asc-正序,desc-倒序,null-默认顺序 */
|
|
4
4
|
export type Order = null | 'asc' | 'desc';
|
|
5
5
|
|
|
6
|
-
type Sorter = boolean | ((data:
|
|
6
|
+
type Sorter<T> = boolean | ((data: T[], option: { order: Order; column: any }) => T[]);
|
|
7
7
|
|
|
8
8
|
export type CustomCellFunc<T extends Record<string, any>> = (props: { row: T; col: StkTableColumn<T>; cellValue: any }) => VNode;
|
|
9
9
|
export type CustomHeaderCellFunc<T extends Record<string, any>> = (props: { col: StkTableColumn<T> }) => VNode;
|
|
@@ -19,7 +19,7 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
19
19
|
/** 表头内容对齐方式 */
|
|
20
20
|
headerAlign?: 'right' | 'left' | 'center';
|
|
21
21
|
/** 筛选 */
|
|
22
|
-
sorter?: Sorter
|
|
22
|
+
sorter?: Sorter<T>;
|
|
23
23
|
/** 列宽。横向虚拟滚动时必须设置。 */
|
|
24
24
|
width?: string;
|
|
25
25
|
/** 最小列宽。非x虚拟滚动生效。 */
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Ref, onBeforeUnmount, onMounted } from 'vue';
|
|
2
|
+
import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
3
|
+
|
|
4
|
+
const ARROW_CODES = ['ArrowUp', 'ArrowRight', 'ArrowDown', 'ArrowLeft'];
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
scrollTo: (x: number | null, y: number | null) => void;
|
|
8
|
+
virtualScroll: Ref<VirtualScrollStore>;
|
|
9
|
+
virtualScrollX: Ref<VirtualScrollXStore>;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* 按下键盘箭头滚动。只有悬浮在表体上才能生效键盘。
|
|
13
|
+
*
|
|
14
|
+
* 在低版本浏览器中,虚拟滚动时,使用键盘滚动,等选中的行消失在视口外时,滚动会失效。
|
|
15
|
+
*/
|
|
16
|
+
export function useKeyboardArrowScroll(targetElement: Ref<HTMLElement | undefined>, { scrollTo, virtualScroll, virtualScrollX }: Options) {
|
|
17
|
+
/** 检测鼠标是否悬浮在表格体上 */
|
|
18
|
+
let isMouseOver = false;
|
|
19
|
+
|
|
20
|
+
onMounted(() => {
|
|
21
|
+
window.addEventListener('keydown', handleKeydown);
|
|
22
|
+
targetElement.value?.addEventListener('mouseenter', handleMouseEnter);
|
|
23
|
+
targetElement.value?.addEventListener('mouseleave', handleMouseLeave);
|
|
24
|
+
targetElement.value?.addEventListener('mousedown', handleMouseDown);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
onBeforeUnmount(() => {
|
|
28
|
+
window.removeEventListener('keydown', handleKeydown);
|
|
29
|
+
targetElement.value?.removeEventListener('mouseenter', handleMouseEnter);
|
|
30
|
+
targetElement.value?.removeEventListener('mouseleave', handleMouseLeave);
|
|
31
|
+
targetElement.value?.removeEventListener('mousedown', handleMouseDown);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/** 键盘按下事件 */
|
|
35
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
36
|
+
if (!ARROW_CODES.includes(e.code)) return;
|
|
37
|
+
if (!isMouseOver) return; // 不悬浮还是要触发键盘事件的
|
|
38
|
+
e.preventDefault(); // 不触发键盘默认的箭头事件
|
|
39
|
+
|
|
40
|
+
const { scrollTop, rowHeight } = virtualScroll.value;
|
|
41
|
+
const { scrollLeft } = virtualScrollX.value;
|
|
42
|
+
if (e.code === ARROW_CODES[0]) {
|
|
43
|
+
scrollTo(scrollTop - rowHeight, null);
|
|
44
|
+
} else if (e.code === ARROW_CODES[1]) {
|
|
45
|
+
scrollTo(null, scrollLeft + rowHeight);
|
|
46
|
+
} else if (e.code === ARROW_CODES[2]) {
|
|
47
|
+
scrollTo(scrollTop + rowHeight, null);
|
|
48
|
+
} else if (e.code === ARROW_CODES[3]) {
|
|
49
|
+
scrollTo(null, scrollLeft - rowHeight);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function handleMouseEnter() {
|
|
54
|
+
isMouseOver = true;
|
|
55
|
+
}
|
|
56
|
+
function handleMouseLeave() {
|
|
57
|
+
isMouseOver = false;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 兜底。
|
|
61
|
+
* 是否存在不触发mouseEnter的时候?
|
|
62
|
+
*/
|
|
63
|
+
function handleMouseDown() {
|
|
64
|
+
if (!isMouseOver) isMouseOver = true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Ref, ShallowRef, computed, ref } from 'vue';
|
|
2
|
-
import { StkTableColumn } from './types';
|
|
3
2
|
import { Default_Col_Width, Default_Table_Height, Default_Table_Width } from './const';
|
|
3
|
+
import { StkTableColumn } from './types';
|
|
4
4
|
|
|
5
5
|
type Option = {
|
|
6
6
|
tableContainer: Ref<HTMLElement | undefined>;
|
|
@@ -9,21 +9,53 @@ type Option = {
|
|
|
9
9
|
tableHeaderLast: Ref<StkTableColumn<any>[]>;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
/** 暂存纵向虚拟滚动的数据 */
|
|
13
|
+
export type VirtualScrollStore = {
|
|
14
|
+
/** 容器高度 */
|
|
15
|
+
containerHeight: number;
|
|
16
|
+
/** 数组开始位置 */
|
|
17
|
+
startIndex: number;
|
|
18
|
+
/** 行高 */
|
|
19
|
+
rowHeight: number;
|
|
20
|
+
/** 表格定位上边距 */
|
|
21
|
+
offsetTop: number;
|
|
22
|
+
/** 纵向滚动条位置,用于判断是横向滚动还是纵向 */
|
|
23
|
+
scrollTop: number;
|
|
24
|
+
};
|
|
25
|
+
/** 暂存横向虚拟滚动的数据 */
|
|
26
|
+
export type VirtualScrollXStore = {
|
|
27
|
+
/** 容器宽度 */
|
|
28
|
+
containerWidth: number;
|
|
29
|
+
/** 开始位置 */
|
|
30
|
+
startIndex: number;
|
|
31
|
+
/** 结束始位置 */
|
|
32
|
+
endIndex: number;
|
|
33
|
+
/** 表格定位左边距 */
|
|
34
|
+
offsetLeft: number;
|
|
35
|
+
/** 横向滚动位置,用于判断是横向滚动还是纵向 */
|
|
36
|
+
scrollLeft: number;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 虚拟滚动
|
|
41
|
+
* @param param0
|
|
42
|
+
* @returns
|
|
43
|
+
*/
|
|
12
44
|
export function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLast }: Option) {
|
|
13
|
-
const virtualScroll = ref({
|
|
45
|
+
const virtualScroll = ref<VirtualScrollStore>({
|
|
14
46
|
containerHeight: 0,
|
|
15
|
-
startIndex: 0,
|
|
47
|
+
startIndex: 0,
|
|
16
48
|
rowHeight: 28,
|
|
17
|
-
offsetTop: 0,
|
|
18
|
-
scrollTop: 0,
|
|
49
|
+
offsetTop: 0,
|
|
50
|
+
scrollTop: 0,
|
|
19
51
|
});
|
|
20
52
|
|
|
21
|
-
const virtualScrollX = ref({
|
|
53
|
+
const virtualScrollX = ref<VirtualScrollXStore>({
|
|
22
54
|
containerWidth: 0,
|
|
23
55
|
startIndex: 0,
|
|
24
56
|
endIndex: 0,
|
|
25
57
|
offsetLeft: 0,
|
|
26
|
-
scrollLeft: 0,
|
|
58
|
+
scrollLeft: 0,
|
|
27
59
|
});
|
|
28
60
|
|
|
29
61
|
const virtual_on = computed(() => {
|
|
@@ -92,9 +124,14 @@ export function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableH
|
|
|
92
124
|
*/
|
|
93
125
|
function initVirtualScrollY(height?: number) {
|
|
94
126
|
if (!virtual_on.value) return;
|
|
127
|
+
const { offsetHeight, scrollTop } = tableContainer.value || {};
|
|
95
128
|
// FIXME: 可能多次获取offsetHeight 会导致浏览器频繁重排
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
if (typeof height === 'number') {
|
|
130
|
+
virtualScroll.value.containerHeight = height;
|
|
131
|
+
} else {
|
|
132
|
+
virtualScroll.value.containerHeight = offsetHeight || Default_Table_Height;
|
|
133
|
+
}
|
|
134
|
+
updateVirtualScrollY(scrollTop);
|
|
98
135
|
}
|
|
99
136
|
|
|
100
137
|
function initVirtualScrollX() {
|
|
@@ -104,6 +141,14 @@ export function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableH
|
|
|
104
141
|
virtualScrollX.value.containerWidth = offsetWidth || Default_Table_Width;
|
|
105
142
|
updateVirtualScrollX(scrollLeft);
|
|
106
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* 初始化虚拟滚动参数
|
|
146
|
+
* @param {number} [height] 虚拟滚动的高度
|
|
147
|
+
*/
|
|
148
|
+
function initVirtualScroll(height?: number) {
|
|
149
|
+
initVirtualScrollY(height);
|
|
150
|
+
initVirtualScrollX();
|
|
151
|
+
}
|
|
107
152
|
|
|
108
153
|
/** 通过滚动条位置,计算虚拟滚动的参数 */
|
|
109
154
|
function updateVirtualScrollY(sTop = 0) {
|
|
@@ -160,6 +205,7 @@ export function useVirtualScroll({ tableContainer, props, dataSourceCopy, tableH
|
|
|
160
205
|
virtualX_on,
|
|
161
206
|
virtualX_columnPart,
|
|
162
207
|
virtualX_offsetRight,
|
|
208
|
+
initVirtualScroll,
|
|
163
209
|
initVirtualScrollY,
|
|
164
210
|
initVirtualScrollX,
|
|
165
211
|
updateVirtualScrollY,
|