stk-table-vue 0.2.7 → 0.2.9
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 +23 -8
- package/lib/src/StkTable/StkTable.vue.d.ts +12 -2
- package/lib/src/StkTable/const.d.ts +12 -8
- package/lib/src/StkTable/types/index.d.ts +18 -0
- package/lib/src/StkTable/useFixedCol.d.ts +2 -1
- package/lib/src/StkTable/useHighlight.d.ts +6 -6
- package/lib/stk-table-vue.js +78 -55
- package/lib/style.css +3 -2
- package/package.json +1 -1
- package/src/StkTable/StkTable.vue +15 -7
- package/src/StkTable/const.ts +13 -8
- package/src/StkTable/style.less +3 -2
- package/src/StkTable/types/index.ts +13 -0
- package/src/StkTable/useFixedCol.ts +17 -14
- package/src/StkTable/useFixedStyle.ts +4 -4
- package/src/StkTable/useHighlight.ts +41 -28
- package/src/StkTable/useVirtualScroll.ts +12 -7
- package/src/StkTable/utils.ts +2 -2
package/README.md
CHANGED
|
@@ -12,7 +12,10 @@ repo:
|
|
|
12
12
|
* [x] props.dataSource 为 shallowRef 时,高亮行不生效。(bug:2024.02.21)(resolved:0.2.3)
|
|
13
13
|
|
|
14
14
|
## Feature TODO:
|
|
15
|
-
* [x]
|
|
15
|
+
* [x] 高亮行,单元格。使用css keyframe实现。
|
|
16
|
+
- [x] 虚拟滚动默认通过js计算行高亮背景色,可通过 `useCss` 设置为css keyframe实现 。
|
|
17
|
+
- [x] 支持配置高亮参数(持续时间,颜色,频率(虚拟滚动))。(`v0.2.9`)
|
|
18
|
+
- [x] `setHighlightDimRow`/`setHighlightCellRow`支持自定义高亮css类名。(`v0.2.9`)
|
|
16
19
|
* [x] 虚拟滚动。
|
|
17
20
|
- [x] 纵向。
|
|
18
21
|
- [x] 横向(必须设置列宽)。
|
|
@@ -29,19 +32,19 @@ repo:
|
|
|
29
32
|
- [x] 基本表头点击排序。
|
|
30
33
|
- [x] 支持配置 `null` | `undefined` 永远排最后。
|
|
31
34
|
- [] 支持配置 string 使用 `String.prototype.localCompare` 排序。
|
|
32
|
-
* 多级表头。
|
|
35
|
+
* [x] 多级表头。
|
|
33
36
|
- [x] 支持最多`2级`表头。
|
|
34
37
|
- [x] 支持更多级表头。
|
|
35
38
|
- [] 横向虚拟滚动。
|
|
36
39
|
* [x] 支持table-layout: fixed 配置。
|
|
37
|
-
* 鼠标悬浮在表格上,键盘滚动虚拟表格。
|
|
40
|
+
* [x] 鼠标悬浮在表格上,键盘滚动虚拟表格。
|
|
38
41
|
- [x] 键盘 `ArrowUp`/`ArrowDown`/`ArrowLeft`/`ArrowRight` 按键支持。
|
|
39
42
|
- [x] 键盘 `PageUp`/ `PageDown` 按键支持。
|
|
40
43
|
* [] 非虚拟滚动时,大数据分批加载。
|
|
41
44
|
* [x] vue2.7支持(引入源码使用)。
|
|
42
|
-
- [x] `props.optimizeVue2Scroll` 优化vue2虚拟滚动流畅度。
|
|
43
|
-
* [x] `props.emptyCellText` 支持传入函数。
|
|
44
|
-
|
|
45
|
+
- [x] `props.optimizeVue2Scroll` 优化vue2虚拟滚动流畅度。(`v0.2.0`)
|
|
46
|
+
* [x] `props.emptyCellText` 支持传入函数。(`v0.2.6`)
|
|
47
|
+
|
|
45
48
|
|
|
46
49
|
|
|
47
50
|
## Usage
|
|
@@ -53,8 +56,8 @@ import { StkTable } from 'stk-table-vue'
|
|
|
53
56
|
import { ref } from 'vue'
|
|
54
57
|
const stkTable = ref<InstanceType<typeof StkTable>>();
|
|
55
58
|
// highlight
|
|
56
|
-
stkTable.value.setHighlightDimRow([rowId]);// highlight row
|
|
57
|
-
stkTable.value.setHighlightDimCell(rowId, colId) // highlight cell
|
|
59
|
+
stkTable.value.setHighlightDimRow([rowId],{useCss:false,className:'custom-class-name'});// highlight row
|
|
60
|
+
stkTable.value.setHighlightDimCell(rowId, colId,{className:'custom-class-name'}) // highlight cell
|
|
58
61
|
</script>
|
|
59
62
|
|
|
60
63
|
<template>
|
|
@@ -199,6 +202,18 @@ export type StkProps = {
|
|
|
199
202
|
},
|
|
200
203
|
/** 隐藏头部title。可传入dataIndex数组 */
|
|
201
204
|
hideHeaderTitle?: boolean | string[];
|
|
205
|
+
/** 高亮配置 */
|
|
206
|
+
highlightConfig?: {
|
|
207
|
+
/** 高亮持续时间(s) */
|
|
208
|
+
duration?: number;
|
|
209
|
+
/** 高亮背景色 */
|
|
210
|
+
color?: {
|
|
211
|
+
light?: { from: string; to: string };
|
|
212
|
+
dark?: { from: string; to: string };
|
|
213
|
+
};
|
|
214
|
+
/** 高亮帧率(虚拟滚动生效) */
|
|
215
|
+
fps?: number;
|
|
216
|
+
};
|
|
202
217
|
};
|
|
203
218
|
```
|
|
204
219
|
#### Emits
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKeyProp } from './types/index';
|
|
1
|
+
import { HighlightConfig, Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKeyProp } from './types/index';
|
|
2
2
|
/** Generic stands for DataType */
|
|
3
3
|
type DT = any;
|
|
4
4
|
/**
|
|
@@ -120,6 +120,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
120
120
|
sortConfig?: SortConfig<any> | undefined;
|
|
121
121
|
/** 隐藏头部title。可传入dataIndex数组 */
|
|
122
122
|
hideHeaderTitle?: boolean | string[] | undefined;
|
|
123
|
+
/** 高亮配置 */
|
|
124
|
+
highlightConfig?: HighlightConfig | undefined;
|
|
123
125
|
}>, {
|
|
124
126
|
width: string;
|
|
125
127
|
fixedMode: boolean;
|
|
@@ -156,6 +158,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
156
158
|
stringLocaleCompare: boolean;
|
|
157
159
|
};
|
|
158
160
|
hideHeaderTitle: boolean;
|
|
161
|
+
highlightConfig: () => {};
|
|
159
162
|
}>, {
|
|
160
163
|
/** 初始化横向纵向虚拟滚动 */
|
|
161
164
|
initVirtualScroll: (height?: number | undefined) => void;
|
|
@@ -166,10 +169,13 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
166
169
|
/** 设置当前选中行 */
|
|
167
170
|
setCurrentRow: typeof setCurrentRow;
|
|
168
171
|
/** 设置高亮渐暗单元格 */
|
|
169
|
-
setHighlightDimCell: (rowKeyValue: string, dataIndex: string
|
|
172
|
+
setHighlightDimCell: (rowKeyValue: string, dataIndex: string, option?: {
|
|
173
|
+
className?: string | undefined;
|
|
174
|
+
}) => void;
|
|
170
175
|
/** 设置高亮渐暗行 */
|
|
171
176
|
setHighlightDimRow: (rowKeyValues: import("./types/index").UniqKey[], option?: {
|
|
172
177
|
useCss?: boolean | undefined;
|
|
178
|
+
className?: string | undefined;
|
|
173
179
|
}) => void;
|
|
174
180
|
/** 表格排序列dataIndex */
|
|
175
181
|
sortCol: import("vue").Ref<string | null | undefined>;
|
|
@@ -285,6 +291,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
285
291
|
sortConfig?: SortConfig<any> | undefined;
|
|
286
292
|
/** 隐藏头部title。可传入dataIndex数组 */
|
|
287
293
|
hideHeaderTitle?: boolean | string[] | undefined;
|
|
294
|
+
/** 高亮配置 */
|
|
295
|
+
highlightConfig?: HighlightConfig | undefined;
|
|
288
296
|
}>, {
|
|
289
297
|
width: string;
|
|
290
298
|
fixedMode: boolean;
|
|
@@ -321,6 +329,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
321
329
|
stringLocaleCompare: boolean;
|
|
322
330
|
};
|
|
323
331
|
hideHeaderTitle: boolean;
|
|
332
|
+
highlightConfig: () => {};
|
|
324
333
|
}>>> & {
|
|
325
334
|
onScroll?: ((ev: Event, data: {
|
|
326
335
|
startIndex: number;
|
|
@@ -375,6 +384,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
375
384
|
optimizeVue2Scroll: boolean;
|
|
376
385
|
sortConfig: SortConfig<any>;
|
|
377
386
|
hideHeaderTitle: boolean | string[];
|
|
387
|
+
highlightConfig: HighlightConfig;
|
|
378
388
|
}, {}>, {
|
|
379
389
|
tableHeader?(_: {
|
|
380
390
|
col: StkTableColumn<any>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
1
|
+
export declare const DEFAULT_COL_WIDTH = "100";
|
|
2
|
+
export declare const DEFAULT_TABLE_HEIGHT = 100;
|
|
3
|
+
export declare const DEFAULT_TABLE_WIDTH = 200;
|
|
4
|
+
export declare const DEFAULT_ROW_HEIGHT = 28;
|
|
5
5
|
/** 高亮背景色 */
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const HIGHLIGHT_COLOR: {
|
|
7
7
|
light: {
|
|
8
8
|
from: string;
|
|
9
9
|
to: string;
|
|
@@ -14,8 +14,12 @@ export declare const Highlight_Color: {
|
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
16
|
/** 高亮持续时间 */
|
|
17
|
-
export declare const
|
|
17
|
+
export declare const HIGHLIGHT_DURATION = 2000;
|
|
18
18
|
/** 高亮变更频率 */
|
|
19
|
-
export declare const
|
|
19
|
+
export declare const HIGHLIGHT_FREQ = 100;
|
|
20
|
+
/** 高亮行class */
|
|
21
|
+
export declare const HIGHLIGHT_ROW_CLASS = "highlight-row";
|
|
22
|
+
/** 高连单元格class */
|
|
23
|
+
export declare const HIGHLIGHT_CELL_CLASS = "highlight-cell";
|
|
20
24
|
/** 是否兼容低版本模式 */
|
|
21
|
-
export declare const
|
|
25
|
+
export declare const IS_LEGACY_MODE: boolean;
|
|
@@ -99,4 +99,22 @@ export declare const enum TagType {
|
|
|
99
99
|
TH = 0,
|
|
100
100
|
TD = 1
|
|
101
101
|
}
|
|
102
|
+
/** 高亮配置 */
|
|
103
|
+
export type HighlightConfig = {
|
|
104
|
+
/** 高亮持续时间(s) */
|
|
105
|
+
duration?: number;
|
|
106
|
+
/** 高亮背景色 */
|
|
107
|
+
color?: {
|
|
108
|
+
light?: {
|
|
109
|
+
from: string;
|
|
110
|
+
to: string;
|
|
111
|
+
};
|
|
112
|
+
dark?: {
|
|
113
|
+
from: string;
|
|
114
|
+
to: string;
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
/** 高亮帧率(虚拟滚动生效) */
|
|
118
|
+
fps?: number;
|
|
119
|
+
};
|
|
102
120
|
export {};
|
|
@@ -3,6 +3,7 @@ import { StkTableColumn } from './types';
|
|
|
3
3
|
type Params<T extends Record<string, any>> = {
|
|
4
4
|
props: any;
|
|
5
5
|
colKeyGen: (col: StkTableColumn<T>) => string;
|
|
6
|
+
tableHeaders: Ref<StkTableColumn<T>[][]>;
|
|
6
7
|
tableHeaderLast: Ref<StkTableColumn<T>[]>;
|
|
7
8
|
tableContainer: Ref<HTMLDivElement | undefined>;
|
|
8
9
|
};
|
|
@@ -10,7 +11,7 @@ type Params<T extends Record<string, any>> = {
|
|
|
10
11
|
* 固定列处理
|
|
11
12
|
* @returns
|
|
12
13
|
*/
|
|
13
|
-
export declare function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen, tableHeaderLast, tableContainer }: Params<DT>): {
|
|
14
|
+
export declare function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen, tableHeaders, tableHeaderLast, tableContainer }: Params<DT>): {
|
|
14
15
|
/** 固定列class */
|
|
15
16
|
fixedColClassMap: import("vue").ComputedRef<Map<any, any>>;
|
|
16
17
|
/** 处理固定列阴影 */
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { Ref } from 'vue';
|
|
2
2
|
import { UniqKey } from './types';
|
|
3
3
|
type Params = {
|
|
4
|
-
props:
|
|
5
|
-
theme: 'light' | 'dark';
|
|
6
|
-
virtual: boolean;
|
|
7
|
-
dataSource: any[];
|
|
8
|
-
};
|
|
4
|
+
props: any;
|
|
9
5
|
tableContainer: Ref<HTMLElement | undefined>;
|
|
10
6
|
};
|
|
11
7
|
/** 高亮行保存的东西 */
|
|
@@ -20,9 +16,13 @@ type HighlightRowStore = {
|
|
|
20
16
|
*/
|
|
21
17
|
export declare function useHighlight({ props, tableContainer }: Params): {
|
|
22
18
|
highlightRowStore: Ref<Record<UniqKey, HighlightRowStore>>;
|
|
19
|
+
highlightFrom: import("vue").ComputedRef<string>;
|
|
23
20
|
setHighlightDimRow: (rowKeyValues: UniqKey[], option?: {
|
|
24
21
|
useCss?: boolean;
|
|
22
|
+
className?: string;
|
|
23
|
+
}) => void;
|
|
24
|
+
setHighlightDimCell: (rowKeyValue: string, dataIndex: string, option?: {
|
|
25
|
+
className?: string;
|
|
25
26
|
}) => void;
|
|
26
|
-
setHighlightDimCell: (rowKeyValue: string, dataIndex: string) => void;
|
|
27
27
|
};
|
|
28
28
|
export {};
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { onMounted, onBeforeUnmount, watch, ref, shallowRef, computed, defineComponent, toRaw, openBlock, createElementBlock, normalizeClass, unref, normalizeStyle, withDirectives, createElementVNode, vShow, Fragment, renderList, createCommentVNode, createBlock, resolveDynamicComponent, renderSlot, toDisplayString, createTextVNode } from "vue";
|
|
2
2
|
import { interpolateRgb } from "d3-interpolate";
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
3
|
+
const DEFAULT_COL_WIDTH = "100";
|
|
4
|
+
const DEFAULT_TABLE_HEIGHT = 100;
|
|
5
|
+
const DEFAULT_TABLE_WIDTH = 200;
|
|
6
|
+
const DEFAULT_ROW_HEIGHT = 28;
|
|
7
|
+
const HIGHLIGHT_COLOR = {
|
|
8
8
|
light: { from: "#71a2fd", to: "#fff" },
|
|
9
9
|
dark: { from: "#1e4c99", to: "#181c21" }
|
|
10
10
|
};
|
|
11
|
-
const
|
|
12
|
-
const
|
|
11
|
+
const HIGHLIGHT_DURATION = 2e3;
|
|
12
|
+
const HIGHLIGHT_FREQ = 100;
|
|
13
|
+
const HIGHLIGHT_ROW_CLASS = "highlight-row";
|
|
14
|
+
const HIGHLIGHT_CELL_CLASS = "highlight-cell";
|
|
13
15
|
let _chromeVersion = 0;
|
|
14
16
|
try {
|
|
15
17
|
const userAgent = navigator.userAgent.match(/chrome\/\d+/i);
|
|
@@ -19,7 +21,7 @@ try {
|
|
|
19
21
|
} catch (e) {
|
|
20
22
|
console.error("Cannot get Chrome version", e);
|
|
21
23
|
}
|
|
22
|
-
const
|
|
24
|
+
const IS_LEGACY_MODE = _chromeVersion < 56;
|
|
23
25
|
var TagType = /* @__PURE__ */ ((TagType2) => {
|
|
24
26
|
TagType2[TagType2["TH"] = 0] = "TH";
|
|
25
27
|
TagType2[TagType2["TD"] = 1] = "TD";
|
|
@@ -197,7 +199,7 @@ function howDeepTheHeader(arr, level = 1) {
|
|
|
197
199
|
return Math.max(...levels);
|
|
198
200
|
}
|
|
199
201
|
function getColWidth(col) {
|
|
200
|
-
const val = (col == null ? void 0 : col.width) ??
|
|
202
|
+
const val = (col == null ? void 0 : col.width) ?? DEFAULT_COL_WIDTH;
|
|
201
203
|
if (typeof val === "number") {
|
|
202
204
|
return Math.floor(val);
|
|
203
205
|
}
|
|
@@ -330,7 +332,7 @@ function useColResize({
|
|
|
330
332
|
onThResizeMouseUp
|
|
331
333
|
};
|
|
332
334
|
}
|
|
333
|
-
function useFixedCol({ props, colKeyGen, tableHeaderLast, tableContainer }) {
|
|
335
|
+
function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableContainer }) {
|
|
334
336
|
const fixedShadow = ref({
|
|
335
337
|
showL: false,
|
|
336
338
|
showR: false
|
|
@@ -338,15 +340,17 @@ function useFixedCol({ props, colKeyGen, tableHeaderLast, tableContainer }) {
|
|
|
338
340
|
const fixedShadowCols = shallowRef([]);
|
|
339
341
|
const fixedColClassMap = computed(() => {
|
|
340
342
|
const colMap = /* @__PURE__ */ new Map();
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
343
|
+
tableHeaders.value.forEach((cols) => {
|
|
344
|
+
cols.forEach((col) => {
|
|
345
|
+
const { showR, showL } = fixedShadow.value;
|
|
346
|
+
const showShadow = props.fixedColShadow && col.fixed && (showL && col.fixed === "left" || showR && col.fixed === "right") && fixedShadowCols.value.includes(col);
|
|
347
|
+
const classObj = {
|
|
348
|
+
"fixed-cell": col.fixed,
|
|
349
|
+
["fixed-cell--" + col.fixed]: col.fixed,
|
|
350
|
+
"fixed-cell--shadow": showShadow
|
|
351
|
+
};
|
|
352
|
+
colMap.set(colKeyGen(col), classObj);
|
|
353
|
+
});
|
|
350
354
|
});
|
|
351
355
|
return colMap;
|
|
352
356
|
});
|
|
@@ -440,13 +444,13 @@ function useFixedStyle({
|
|
|
440
444
|
const isFixedLeft = fixed === "left";
|
|
441
445
|
const style = {};
|
|
442
446
|
const { colKeyStore, refStore } = fixedColumnsPositionStore.value;
|
|
443
|
-
if (
|
|
447
|
+
if (IS_LEGACY_MODE) {
|
|
444
448
|
style.position = "relative";
|
|
445
449
|
} else {
|
|
446
450
|
style.position = "sticky";
|
|
447
451
|
}
|
|
448
452
|
if (tagType === TagType.TH) {
|
|
449
|
-
if (
|
|
453
|
+
if (IS_LEGACY_MODE) {
|
|
450
454
|
style.top = virtualScroll.value.scrollTop + depth * props.rowHeight + "px";
|
|
451
455
|
} else {
|
|
452
456
|
style.top = depth * props.rowHeight + "px";
|
|
@@ -456,7 +460,7 @@ function useFixedStyle({
|
|
|
456
460
|
style.zIndex = isFixedLeft ? "3" : "2";
|
|
457
461
|
}
|
|
458
462
|
if (fixed === "left" || fixed === "right") {
|
|
459
|
-
if (
|
|
463
|
+
if (IS_LEGACY_MODE) {
|
|
460
464
|
if (isFixedLeft) {
|
|
461
465
|
if (virtualX_on.value)
|
|
462
466
|
style.left = virtualScrollX.value.scrollLeft - virtualScrollX.value.offsetLeft + "px";
|
|
@@ -480,12 +484,18 @@ function useFixedStyle({
|
|
|
480
484
|
getFixedStyle
|
|
481
485
|
};
|
|
482
486
|
}
|
|
483
|
-
const HIGHLIGHT_ROW_CLASS = "highlight-row";
|
|
484
|
-
const HIGHLIGHT_CELL_CLASS = "highlight-cell";
|
|
485
487
|
function useHighlight({ props, tableContainer }) {
|
|
488
|
+
var _a, _b;
|
|
489
|
+
const config = props.highlightConfig;
|
|
486
490
|
const highlightRowStore = ref({});
|
|
487
|
-
const
|
|
488
|
-
const
|
|
491
|
+
const duration = config.duration ? config.duration * 1e3 : HIGHLIGHT_DURATION;
|
|
492
|
+
const frequency = config.fps ? 1e3 / config.fps : HIGHLIGHT_FREQ;
|
|
493
|
+
const highlightColor = {
|
|
494
|
+
light: Object.assign(HIGHLIGHT_COLOR.light, (_a = config.color) == null ? void 0 : _a.light),
|
|
495
|
+
dark: Object.assign(HIGHLIGHT_COLOR.dark, (_b = config.color) == null ? void 0 : _b.dark)
|
|
496
|
+
};
|
|
497
|
+
const highlightFrom = computed(() => highlightColor[props.theme].from);
|
|
498
|
+
const highlightTo = computed(() => highlightColor[props.theme].to);
|
|
489
499
|
const highlightInter = computed(() => interpolateRgb(highlightFrom.value, highlightTo.value));
|
|
490
500
|
const highlightDimRowKeys = /* @__PURE__ */ new Set();
|
|
491
501
|
const highlightDimRowsTimeout = /* @__PURE__ */ new Map();
|
|
@@ -500,7 +510,7 @@ function useHighlight({ props, tableContainer }) {
|
|
|
500
510
|
const nowTs = Date.now();
|
|
501
511
|
highlightDimRowKeys.forEach((rowKeyValue) => {
|
|
502
512
|
const highlightItem = highlightRowStore.value[rowKeyValue];
|
|
503
|
-
const progress = (nowTs - highlightItem.bgc_progress_ms) /
|
|
513
|
+
const progress = (nowTs - highlightItem.bgc_progress_ms) / duration;
|
|
504
514
|
if (0 < progress && progress < 1) {
|
|
505
515
|
highlightItem.bgc = highlightInter.value(progress);
|
|
506
516
|
} else {
|
|
@@ -514,34 +524,36 @@ function useHighlight({ props, tableContainer }) {
|
|
|
514
524
|
} else {
|
|
515
525
|
calcHighlightDimLoop = false;
|
|
516
526
|
}
|
|
517
|
-
},
|
|
527
|
+
}, frequency);
|
|
518
528
|
};
|
|
519
529
|
recursion();
|
|
520
530
|
}
|
|
521
|
-
function setHighlightDimCell(rowKeyValue, dataIndex) {
|
|
522
|
-
var
|
|
523
|
-
const cellEl = (
|
|
531
|
+
function setHighlightDimCell(rowKeyValue, dataIndex, option = {}) {
|
|
532
|
+
var _a2;
|
|
533
|
+
const cellEl = (_a2 = tableContainer.value) == null ? void 0 : _a2.querySelector(`[data-row-key="${rowKeyValue}"]>[data-index="${dataIndex}"]`);
|
|
534
|
+
const opt = { className: HIGHLIGHT_CELL_CLASS, ...option };
|
|
524
535
|
if (!cellEl)
|
|
525
536
|
return;
|
|
526
|
-
if (cellEl.classList.contains(
|
|
527
|
-
cellEl.classList.remove(
|
|
537
|
+
if (cellEl.classList.contains(opt.className)) {
|
|
538
|
+
cellEl.classList.remove(opt.className);
|
|
528
539
|
void cellEl.offsetHeight;
|
|
529
540
|
}
|
|
530
|
-
cellEl.classList.add(
|
|
541
|
+
cellEl.classList.add(opt.className);
|
|
531
542
|
window.clearTimeout(highlightDimCellsTimeout.get(rowKeyValue));
|
|
532
543
|
highlightDimCellsTimeout.set(
|
|
533
544
|
rowKeyValue,
|
|
534
545
|
window.setTimeout(() => {
|
|
535
|
-
cellEl.classList.remove(
|
|
546
|
+
cellEl.classList.remove(opt.className);
|
|
536
547
|
highlightDimCellsTimeout.delete(rowKeyValue);
|
|
537
|
-
},
|
|
548
|
+
}, duration)
|
|
538
549
|
);
|
|
539
550
|
}
|
|
540
551
|
function setHighlightDimRow(rowKeyValues, option = {}) {
|
|
541
|
-
var
|
|
552
|
+
var _a2, _b2;
|
|
542
553
|
if (!Array.isArray(rowKeyValues))
|
|
543
554
|
rowKeyValues = [rowKeyValues];
|
|
544
|
-
|
|
555
|
+
const { className, useCss } = { className: HIGHLIGHT_ROW_CLASS, useCss: false, ...option };
|
|
556
|
+
if (props.virtual && !useCss) {
|
|
545
557
|
const nowTs = Date.now();
|
|
546
558
|
for (let i = 0; i < rowKeyValues.length; i++) {
|
|
547
559
|
const rowKeyValue = rowKeyValues[i];
|
|
@@ -558,11 +570,11 @@ function useHighlight({ props, tableContainer }) {
|
|
|
558
570
|
const rowElTemp = [];
|
|
559
571
|
for (let i = 0; i < rowKeyValues.length; i++) {
|
|
560
572
|
const rowKeyValue = rowKeyValues[i];
|
|
561
|
-
const rowEl = (
|
|
573
|
+
const rowEl = (_a2 = tableContainer.value) == null ? void 0 : _a2.querySelector(`[data-row-key="${rowKeyValue}"]`);
|
|
562
574
|
if (!rowEl)
|
|
563
575
|
continue;
|
|
564
|
-
if (rowEl.classList.contains(
|
|
565
|
-
rowEl.classList.remove(
|
|
576
|
+
if (rowEl.classList.contains(className)) {
|
|
577
|
+
rowEl.classList.remove(className);
|
|
566
578
|
needRepaint = true;
|
|
567
579
|
}
|
|
568
580
|
rowElTemp.push(rowEl);
|
|
@@ -570,19 +582,20 @@ function useHighlight({ props, tableContainer }) {
|
|
|
570
582
|
highlightDimRowsTimeout.set(
|
|
571
583
|
rowKeyValue,
|
|
572
584
|
window.setTimeout(() => {
|
|
573
|
-
rowEl.classList.remove(
|
|
585
|
+
rowEl.classList.remove(className);
|
|
574
586
|
highlightDimRowsTimeout.delete(rowKeyValue);
|
|
575
|
-
},
|
|
587
|
+
}, duration)
|
|
576
588
|
);
|
|
577
589
|
}
|
|
578
590
|
if (needRepaint) {
|
|
579
|
-
void ((
|
|
591
|
+
void ((_b2 = tableContainer.value) == null ? void 0 : _b2.offsetWidth);
|
|
580
592
|
}
|
|
581
|
-
rowElTemp.forEach((el) => el.classList.add(
|
|
593
|
+
rowElTemp.forEach((el) => el.classList.add(className));
|
|
582
594
|
}
|
|
583
595
|
}
|
|
584
596
|
return {
|
|
585
597
|
highlightRowStore,
|
|
598
|
+
highlightFrom,
|
|
586
599
|
setHighlightDimRow,
|
|
587
600
|
setHighlightDimCell
|
|
588
601
|
};
|
|
@@ -774,7 +787,7 @@ function useVirtualScroll({
|
|
|
774
787
|
if (typeof height === "number") {
|
|
775
788
|
containerHeight = height;
|
|
776
789
|
} else {
|
|
777
|
-
containerHeight = offsetHeight ||
|
|
790
|
+
containerHeight = offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
778
791
|
}
|
|
779
792
|
const { headless, headerRowHeight } = props;
|
|
780
793
|
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
@@ -789,7 +802,7 @@ function useVirtualScroll({
|
|
|
789
802
|
if (!props.virtualX)
|
|
790
803
|
return;
|
|
791
804
|
const { offsetWidth, scrollLeft } = tableContainer.value || {};
|
|
792
|
-
virtualScrollX.value.containerWidth = offsetWidth ||
|
|
805
|
+
virtualScrollX.value.containerWidth = offsetWidth || DEFAULT_TABLE_WIDTH;
|
|
793
806
|
updateVirtualScrollX(scrollLeft);
|
|
794
807
|
}
|
|
795
808
|
function initVirtualScroll(height) {
|
|
@@ -849,12 +862,15 @@ function useVirtualScroll({
|
|
|
849
862
|
let startIndex = 0;
|
|
850
863
|
let offsetLeft = 0;
|
|
851
864
|
let colWidthSum = 0;
|
|
865
|
+
let leftColWidthSum = 0;
|
|
852
866
|
for (let colIndex = 0; colIndex < headerLength; colIndex++) {
|
|
853
867
|
startIndex++;
|
|
854
868
|
const col = tableHeaderLast.value[colIndex];
|
|
855
|
-
if (col.fixed === "left")
|
|
856
|
-
continue;
|
|
857
869
|
const colWidth = getColWidth(col);
|
|
870
|
+
if (col.fixed === "left") {
|
|
871
|
+
leftColWidthSum += colWidth;
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
858
874
|
colWidthSum += colWidth;
|
|
859
875
|
if (colWidthSum >= sLeft) {
|
|
860
876
|
offsetLeft = colWidthSum - colWidth;
|
|
@@ -863,11 +879,12 @@ function useVirtualScroll({
|
|
|
863
879
|
}
|
|
864
880
|
}
|
|
865
881
|
colWidthSum = 0;
|
|
882
|
+
const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
|
|
866
883
|
let endIndex = headerLength;
|
|
867
884
|
for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
|
|
868
885
|
const col = tableHeaderLast.value[colIndex];
|
|
869
886
|
colWidthSum += getColWidth(col);
|
|
870
|
-
if (colWidthSum >=
|
|
887
|
+
if (colWidthSum >= containerWidth) {
|
|
871
888
|
endIndex = colIndex + 1;
|
|
872
889
|
break;
|
|
873
890
|
}
|
|
@@ -956,7 +973,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
956
973
|
fixedMode: { type: Boolean, default: false },
|
|
957
974
|
headless: { type: Boolean, default: false },
|
|
958
975
|
theme: { default: "light" },
|
|
959
|
-
rowHeight: { default:
|
|
976
|
+
rowHeight: { default: DEFAULT_ROW_HEIGHT },
|
|
960
977
|
headerRowHeight: { default: null },
|
|
961
978
|
virtual: { type: Boolean, default: false },
|
|
962
979
|
virtualX: { type: Boolean, default: false },
|
|
@@ -983,7 +1000,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
983
1000
|
emptyToBottom: false,
|
|
984
1001
|
stringLocaleCompare: true
|
|
985
1002
|
}) },
|
|
986
|
-
hideHeaderTitle: { type: [Boolean, Array], default: false }
|
|
1003
|
+
hideHeaderTitle: { type: [Boolean, Array], default: false },
|
|
1004
|
+
highlightConfig: { default: () => ({}) }
|
|
987
1005
|
},
|
|
988
1006
|
emits: ["sort-change", "row-click", "current-change", "row-dblclick", "header-row-menu", "row-menu", "cell-click", "header-cell-click", "scroll", "scroll-x", "col-order-change", "th-drag-start", "th-drop", "update:columns"],
|
|
989
1007
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
@@ -1040,7 +1058,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1040
1058
|
virtualX_on,
|
|
1041
1059
|
virtualX_offsetRight
|
|
1042
1060
|
});
|
|
1043
|
-
const { highlightRowStore, setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer });
|
|
1061
|
+
const { highlightRowStore, highlightFrom, setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer });
|
|
1044
1062
|
if (props.autoResize) {
|
|
1045
1063
|
useAutoResize({ tableContainer, initVirtualScroll, props, debounceMs: 200 });
|
|
1046
1064
|
}
|
|
@@ -1055,6 +1073,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1055
1073
|
props,
|
|
1056
1074
|
colKeyGen,
|
|
1057
1075
|
tableContainer,
|
|
1076
|
+
tableHeaders,
|
|
1058
1077
|
tableHeaderLast
|
|
1059
1078
|
});
|
|
1060
1079
|
watch(
|
|
@@ -1386,12 +1405,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1386
1405
|
"border-body-v": props.bordered === "body-v",
|
|
1387
1406
|
stripe: props.stripe
|
|
1388
1407
|
}]),
|
|
1389
|
-
style: normalizeStyle(
|
|
1408
|
+
style: normalizeStyle([
|
|
1390
1409
|
_ctx.virtual && {
|
|
1391
1410
|
"--row-height": unref(virtualScroll).rowHeight + "px",
|
|
1392
1411
|
"--header-row-height": (props.headerRowHeight || props.rowHeight) + "px"
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
"--highlight-color": props.highlightConfig.color && unref(highlightFrom),
|
|
1415
|
+
"--highlight-duration": props.highlightConfig.duration && props.highlightConfig.duration + "s"
|
|
1393
1416
|
}
|
|
1394
|
-
),
|
|
1417
|
+
]),
|
|
1395
1418
|
onScroll: onTableScroll,
|
|
1396
1419
|
onWheel: onTableWheel
|
|
1397
1420
|
}, [
|
package/lib/style.css
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
--bg-border-bottom:linear-gradient(0deg, var(--border-color) var(--border-width), transparent var(--border-width));
|
|
21
21
|
--bg-border-left:linear-gradient(90deg, var(--border-color) var(--border-width), transparent var(--border-width));
|
|
22
22
|
--highlight-color:#71a2fd;
|
|
23
|
+
--highlight-duration:2s;
|
|
23
24
|
--stripe-bgc:#fafafc;
|
|
24
25
|
--sort-arrow-color:#757699;
|
|
25
26
|
--sort-arrow-hover-color:#8f90b5;
|
|
@@ -148,7 +149,7 @@
|
|
|
148
149
|
background-color:inherit;
|
|
149
150
|
}
|
|
150
151
|
.stk-table .stk-table-main td.highlight-cell{
|
|
151
|
-
animation:stk-table-dim
|
|
152
|
+
animation:stk-table-dim var(--highlight-duration) linear;
|
|
152
153
|
}
|
|
153
154
|
.stk-table .stk-table-main td.text-overflow .table-cell-wrapper{
|
|
154
155
|
white-space:nowrap;
|
|
@@ -247,7 +248,7 @@
|
|
|
247
248
|
height:var(--row-height);
|
|
248
249
|
}
|
|
249
250
|
.stk-table .stk-table-main tbody tr.highlight-row{
|
|
250
|
-
animation:stk-table-dim
|
|
251
|
+
animation:stk-table-dim var(--highlight-duration) linear;
|
|
251
252
|
}
|
|
252
253
|
.stk-table .stk-table-main tbody tr.hover,
|
|
253
254
|
.stk-table .stk-table-main tbody tr:hover{
|
package/package.json
CHANGED
|
@@ -15,12 +15,16 @@
|
|
|
15
15
|
'border-body-v': props.bordered === 'body-v',
|
|
16
16
|
stripe: props.stripe,
|
|
17
17
|
}"
|
|
18
|
-
:style="
|
|
18
|
+
:style="[
|
|
19
19
|
virtual && {
|
|
20
20
|
'--row-height': virtualScroll.rowHeight + 'px',
|
|
21
21
|
'--header-row-height': (props.headerRowHeight || props.rowHeight) + 'px',
|
|
22
|
-
}
|
|
23
|
-
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
'--highlight-color': props.highlightConfig.color && highlightFrom,
|
|
25
|
+
'--highlight-duration': props.highlightConfig.duration && props.highlightConfig.duration + 's',
|
|
26
|
+
},
|
|
27
|
+
]"
|
|
24
28
|
@scroll="onTableScroll"
|
|
25
29
|
@wheel="onTableWheel"
|
|
26
30
|
>
|
|
@@ -190,8 +194,8 @@
|
|
|
190
194
|
* [] highlight-row 颜色不能恢复到active的颜色
|
|
191
195
|
*/
|
|
192
196
|
import { CSSProperties, computed, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
|
|
193
|
-
import {
|
|
194
|
-
import { Order, SortConfig, SortOption, SortState, StkTableColumn, TagType, UniqKeyProp } from './types/index';
|
|
197
|
+
import { DEFAULT_ROW_HEIGHT } from './const';
|
|
198
|
+
import { HighlightConfig, Order, SortConfig, SortOption, SortState, StkTableColumn, TagType, UniqKeyProp } from './types/index';
|
|
195
199
|
import { useAutoResize } from './useAutoResize';
|
|
196
200
|
import { useColResize } from './useColResize';
|
|
197
201
|
import { useFixedCol } from './useFixedCol';
|
|
@@ -289,6 +293,8 @@ const props = withDefaults(
|
|
|
289
293
|
sortConfig?: SortConfig<DT>;
|
|
290
294
|
/** 隐藏头部title。可传入dataIndex数组 */
|
|
291
295
|
hideHeaderTitle?: boolean | string[];
|
|
296
|
+
/** 高亮配置 */
|
|
297
|
+
highlightConfig?: HighlightConfig;
|
|
292
298
|
}>(),
|
|
293
299
|
{
|
|
294
300
|
width: '',
|
|
@@ -298,7 +304,7 @@ const props = withDefaults(
|
|
|
298
304
|
maxWidth: '',
|
|
299
305
|
headless: false,
|
|
300
306
|
theme: 'light',
|
|
301
|
-
rowHeight:
|
|
307
|
+
rowHeight: DEFAULT_ROW_HEIGHT,
|
|
302
308
|
headerRowHeight: null,
|
|
303
309
|
virtual: false,
|
|
304
310
|
virtualX: false,
|
|
@@ -326,6 +332,7 @@ const props = withDefaults(
|
|
|
326
332
|
stringLocaleCompare: true,
|
|
327
333
|
}),
|
|
328
334
|
hideHeaderTitle: false,
|
|
335
|
+
highlightConfig: () => ({}),
|
|
329
336
|
},
|
|
330
337
|
);
|
|
331
338
|
|
|
@@ -497,7 +504,7 @@ const { getFixedStyle } = useFixedStyle<DT>({
|
|
|
497
504
|
/**
|
|
498
505
|
* 高亮行,高亮单元格
|
|
499
506
|
*/
|
|
500
|
-
const { highlightRowStore, setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer });
|
|
507
|
+
const { highlightRowStore, highlightFrom, setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer });
|
|
501
508
|
|
|
502
509
|
if (props.autoResize) {
|
|
503
510
|
useAutoResize({ tableContainer, initVirtualScroll, props, debounceMs: 200 });
|
|
@@ -517,6 +524,7 @@ const { fixedColClassMap, dealFixedColShadow, updateFixedShadow } = useFixedCol(
|
|
|
517
524
|
props,
|
|
518
525
|
colKeyGen,
|
|
519
526
|
tableContainer,
|
|
527
|
+
tableHeaders,
|
|
520
528
|
tableHeaderLast,
|
|
521
529
|
});
|
|
522
530
|
|
package/src/StkTable/const.ts
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const DEFAULT_COL_WIDTH = '100';
|
|
2
2
|
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
5
|
-
export const
|
|
3
|
+
export const DEFAULT_TABLE_HEIGHT = 100;
|
|
4
|
+
export const DEFAULT_TABLE_WIDTH = 200;
|
|
5
|
+
export const DEFAULT_ROW_HEIGHT = 28;
|
|
6
6
|
|
|
7
7
|
/** 高亮背景色 */
|
|
8
|
-
export const
|
|
8
|
+
export const HIGHLIGHT_COLOR = {
|
|
9
9
|
light: { from: '#71a2fd', to: '#fff' },
|
|
10
10
|
dark: { from: '#1e4c99', to: '#181c21' },
|
|
11
11
|
};
|
|
12
12
|
/** 高亮持续时间 */
|
|
13
|
-
export const
|
|
13
|
+
export const HIGHLIGHT_DURATION = 2000;
|
|
14
14
|
/** 高亮变更频率 */
|
|
15
|
-
export const
|
|
15
|
+
export const HIGHLIGHT_FREQ = 100;
|
|
16
|
+
|
|
17
|
+
/** 高亮行class */
|
|
18
|
+
export const HIGHLIGHT_ROW_CLASS = 'highlight-row';
|
|
19
|
+
/** 高连单元格class */
|
|
20
|
+
export const HIGHLIGHT_CELL_CLASS = 'highlight-cell';
|
|
16
21
|
|
|
17
22
|
let _chromeVersion = 0;
|
|
18
23
|
try {
|
|
@@ -24,4 +29,4 @@ try {
|
|
|
24
29
|
console.error('Cannot get Chrome version', e);
|
|
25
30
|
}
|
|
26
31
|
/** 是否兼容低版本模式 */
|
|
27
|
-
export const
|
|
32
|
+
export const IS_LEGACY_MODE = _chromeVersion < 56;
|
package/src/StkTable/style.less
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
--bg-border-bottom: linear-gradient(0deg, var(--border-color) var(--border-width), transparent var(--border-width));
|
|
24
24
|
--bg-border-left: linear-gradient(90deg, var(--border-color) var(--border-width), transparent var(--border-width));
|
|
25
25
|
--highlight-color: #71a2fd;
|
|
26
|
+
--highlight-duration: 2s;
|
|
26
27
|
/* 斑马纹颜色*/
|
|
27
28
|
--stripe-bgc: #fafafc;
|
|
28
29
|
|
|
@@ -211,7 +212,7 @@
|
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
&.highlight-cell {
|
|
214
|
-
animation: stk-table-dim
|
|
215
|
+
animation: stk-table-dim var(--highlight-duration) linear;
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
&.text-overflow {
|
|
@@ -351,7 +352,7 @@
|
|
|
351
352
|
|
|
352
353
|
/* td inherit tr bgc*/
|
|
353
354
|
&.highlight-row {
|
|
354
|
-
animation: stk-table-dim
|
|
355
|
+
animation: stk-table-dim var(--highlight-duration) linear;
|
|
355
356
|
}
|
|
356
357
|
|
|
357
358
|
/* &.highlight-row-transition {
|
|
@@ -99,3 +99,16 @@ export const enum TagType {
|
|
|
99
99
|
TH,
|
|
100
100
|
TD,
|
|
101
101
|
}
|
|
102
|
+
|
|
103
|
+
/** 高亮配置 */
|
|
104
|
+
export type HighlightConfig = {
|
|
105
|
+
/** 高亮持续时间(s) */
|
|
106
|
+
duration?: number;
|
|
107
|
+
/** 高亮背景色 */
|
|
108
|
+
color?: {
|
|
109
|
+
light?: { from: string; to: string };
|
|
110
|
+
dark?: { from: string; to: string };
|
|
111
|
+
};
|
|
112
|
+
/** 高亮帧率(虚拟滚动生效) */
|
|
113
|
+
fps?: number;
|
|
114
|
+
};
|
|
@@ -4,6 +4,7 @@ import { StkTableColumn } from './types';
|
|
|
4
4
|
type Params<T extends Record<string, any>> = {
|
|
5
5
|
props: any;
|
|
6
6
|
colKeyGen: (col: StkTableColumn<T>) => string;
|
|
7
|
+
tableHeaders: Ref<StkTableColumn<T>[][]>;
|
|
7
8
|
tableHeaderLast: Ref<StkTableColumn<T>[]>;
|
|
8
9
|
tableContainer: Ref<HTMLDivElement | undefined>;
|
|
9
10
|
};
|
|
@@ -12,7 +13,7 @@ type Params<T extends Record<string, any>> = {
|
|
|
12
13
|
* 固定列处理
|
|
13
14
|
* @returns
|
|
14
15
|
*/
|
|
15
|
-
export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen, tableHeaderLast, tableContainer }: Params<DT>) {
|
|
16
|
+
export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen, tableHeaders, tableHeaderLast, tableContainer }: Params<DT>) {
|
|
16
17
|
/** 固定列阴影 */
|
|
17
18
|
const fixedShadow = ref<{
|
|
18
19
|
/** 是否展示左侧固定列阴影 */
|
|
@@ -28,19 +29,21 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
|
|
|
28
29
|
|
|
29
30
|
const fixedColClassMap = computed(() => {
|
|
30
31
|
const colMap = new Map();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
tableHeaders.value.forEach(cols => {
|
|
33
|
+
cols.forEach(col => {
|
|
34
|
+
const { showR, showL } = fixedShadow.value;
|
|
35
|
+
const showShadow =
|
|
36
|
+
props.fixedColShadow &&
|
|
37
|
+
col.fixed &&
|
|
38
|
+
((showL && col.fixed === 'left') || (showR && col.fixed === 'right')) &&
|
|
39
|
+
fixedShadowCols.value.includes(col);
|
|
40
|
+
const classObj = {
|
|
41
|
+
'fixed-cell': col.fixed,
|
|
42
|
+
['fixed-cell--' + col.fixed]: col.fixed,
|
|
43
|
+
'fixed-cell--shadow': showShadow,
|
|
44
|
+
};
|
|
45
|
+
colMap.set(colKeyGen(col), classObj);
|
|
46
|
+
});
|
|
44
47
|
});
|
|
45
48
|
return colMap;
|
|
46
49
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CSSProperties, Ref, computed } from 'vue';
|
|
2
|
-
import {
|
|
2
|
+
import { IS_LEGACY_MODE } from './const';
|
|
3
3
|
import { StkTableColumn, TagType } from './types';
|
|
4
4
|
import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
5
5
|
import { getColWidth } from './utils';
|
|
@@ -77,14 +77,14 @@ export function useFixedStyle<DT extends Record<string, any>>({
|
|
|
77
77
|
const style: CSSProperties = {};
|
|
78
78
|
const { colKeyStore, refStore } = fixedColumnsPositionStore.value;
|
|
79
79
|
|
|
80
|
-
if (
|
|
80
|
+
if (IS_LEGACY_MODE) {
|
|
81
81
|
style.position = 'relative';
|
|
82
82
|
} else {
|
|
83
83
|
style.position = 'sticky';
|
|
84
84
|
}
|
|
85
85
|
if (tagType === TagType.TH) {
|
|
86
86
|
// TH
|
|
87
|
-
if (
|
|
87
|
+
if (IS_LEGACY_MODE) {
|
|
88
88
|
style.top = virtualScroll.value.scrollTop + depth * props.rowHeight + 'px';
|
|
89
89
|
} else {
|
|
90
90
|
style.top = depth * props.rowHeight + 'px';
|
|
@@ -96,7 +96,7 @@ export function useFixedStyle<DT extends Record<string, any>>({
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
if (fixed === 'left' || fixed === 'right') {
|
|
99
|
-
if (
|
|
99
|
+
if (IS_LEGACY_MODE) {
|
|
100
100
|
if (isFixedLeft) {
|
|
101
101
|
if (virtualX_on.value) style.left = virtualScrollX.value.scrollLeft - virtualScrollX.value.offsetLeft + 'px';
|
|
102
102
|
else style.left = virtualScrollX.value.scrollLeft + 'px';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { interpolateRgb } from 'd3-interpolate';
|
|
2
2
|
import { Ref, computed, ref } from 'vue';
|
|
3
|
-
import {
|
|
4
|
-
import { UniqKey } from './types';
|
|
3
|
+
import { HIGHLIGHT_CELL_CLASS, HIGHLIGHT_COLOR, HIGHLIGHT_DURATION, HIGHLIGHT_FREQ, HIGHLIGHT_ROW_CLASS } from './const';
|
|
4
|
+
import { HighlightConfig, UniqKey } from './types';
|
|
5
5
|
|
|
6
6
|
type Params = {
|
|
7
|
-
props:
|
|
7
|
+
props: any;
|
|
8
8
|
tableContainer: Ref<HTMLElement | undefined>;
|
|
9
9
|
};
|
|
10
10
|
|
|
@@ -15,23 +15,28 @@ type HighlightRowStore = {
|
|
|
15
15
|
bgc_progress: number;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
/** 高亮行class */
|
|
19
|
-
const HIGHLIGHT_ROW_CLASS = 'highlight-row';
|
|
20
|
-
/** 高连单元格class */
|
|
21
|
-
const HIGHLIGHT_CELL_CLASS = 'highlight-cell';
|
|
22
|
-
|
|
23
18
|
/**
|
|
24
19
|
* 高亮单元格,行
|
|
25
20
|
* row中新增_bgc_progress_ms 属性控制高亮状态,_bgc控制颜色
|
|
26
21
|
*/
|
|
27
22
|
export function useHighlight({ props, tableContainer }: Params) {
|
|
23
|
+
const config: HighlightConfig = props.highlightConfig;
|
|
28
24
|
/**
|
|
29
25
|
* 高亮行记录 key-rowKey, value-obj
|
|
30
26
|
*/
|
|
31
27
|
const highlightRowStore = ref<Record<UniqKey, HighlightRowStore>>({});
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
28
|
+
/** 持续时间 */
|
|
29
|
+
const duration = config.duration ? config.duration * 1000 : HIGHLIGHT_DURATION;
|
|
30
|
+
/** 频率 */
|
|
31
|
+
const frequency = config.fps ? 1000 / config.fps : HIGHLIGHT_FREQ;
|
|
32
|
+
const highlightColor = {
|
|
33
|
+
light: Object.assign(HIGHLIGHT_COLOR.light, config.color?.light),
|
|
34
|
+
dark: Object.assign(HIGHLIGHT_COLOR.dark, config.color?.dark),
|
|
35
|
+
};
|
|
36
|
+
/** 高亮开始 */
|
|
37
|
+
const highlightFrom = computed(() => highlightColor[props.theme as 'light' | 'dark'].from);
|
|
38
|
+
/** 高亮结束 */
|
|
39
|
+
const highlightTo = computed(() => highlightColor[props.theme as 'light' | 'dark'].to);
|
|
35
40
|
const highlightInter = computed(() => interpolateRgb(highlightFrom.value, highlightTo.value));
|
|
36
41
|
|
|
37
42
|
/** 存放高亮行的key*/
|
|
@@ -67,7 +72,7 @@ export function useHighlight({ props, tableContainer }: Params) {
|
|
|
67
72
|
// }
|
|
68
73
|
const highlightItem = highlightRowStore.value[rowKeyValue];
|
|
69
74
|
/** 经过的时间 ÷ 高亮持续时间 计算出 颜色过渡进度 (0-1) */
|
|
70
|
-
const progress = (nowTs - highlightItem.bgc_progress_ms) /
|
|
75
|
+
const progress = (nowTs - highlightItem.bgc_progress_ms) / duration;
|
|
71
76
|
if (0 < progress && progress < 1) {
|
|
72
77
|
highlightItem.bgc = highlightInter.value(progress);
|
|
73
78
|
} else {
|
|
@@ -86,39 +91,46 @@ export function useHighlight({ props, tableContainer }: Params) {
|
|
|
86
91
|
// 没有则停止循环
|
|
87
92
|
calcHighlightDimLoop = false;
|
|
88
93
|
}
|
|
89
|
-
},
|
|
94
|
+
}, frequency);
|
|
90
95
|
};
|
|
91
96
|
recursion();
|
|
92
97
|
}
|
|
93
98
|
|
|
94
|
-
/**
|
|
95
|
-
|
|
99
|
+
/**
|
|
100
|
+
* 高亮一个单元格
|
|
101
|
+
* @param rowKeyValue 一行的key
|
|
102
|
+
* @param dataIndex 列key
|
|
103
|
+
* @param option.className 高亮类名
|
|
104
|
+
*/
|
|
105
|
+
function setHighlightDimCell(rowKeyValue: string, dataIndex: string, option: { className?: string } = {}) {
|
|
96
106
|
// TODO: 支持动态计算高亮颜色。不易实现。需记录每一个单元格的颜色情况。
|
|
97
107
|
const cellEl = tableContainer.value?.querySelector<HTMLElement>(`[data-row-key="${rowKeyValue}"]>[data-index="${dataIndex}"]`);
|
|
108
|
+
const opt = { className: HIGHLIGHT_CELL_CLASS, ...option };
|
|
98
109
|
if (!cellEl) return;
|
|
99
|
-
if (cellEl.classList.contains(
|
|
100
|
-
cellEl.classList.remove(
|
|
110
|
+
if (cellEl.classList.contains(opt.className)) {
|
|
111
|
+
cellEl.classList.remove(opt.className);
|
|
101
112
|
void cellEl.offsetHeight; // 通知浏览器重绘
|
|
102
113
|
}
|
|
103
|
-
cellEl.classList.add(
|
|
114
|
+
cellEl.classList.add(opt.className);
|
|
104
115
|
window.clearTimeout(highlightDimCellsTimeout.get(rowKeyValue));
|
|
105
116
|
highlightDimCellsTimeout.set(
|
|
106
117
|
rowKeyValue,
|
|
107
118
|
window.setTimeout(() => {
|
|
108
|
-
cellEl.classList.remove(
|
|
119
|
+
cellEl.classList.remove(opt.className);
|
|
109
120
|
highlightDimCellsTimeout.delete(rowKeyValue);
|
|
110
|
-
},
|
|
121
|
+
}, duration),
|
|
111
122
|
);
|
|
112
123
|
}
|
|
113
124
|
|
|
114
125
|
/**
|
|
115
126
|
* 高亮一行
|
|
116
|
-
* @param rowKeyValues
|
|
127
|
+
* @param rowKeyValues 行唯一键的数组
|
|
117
128
|
* @param option.useCss 虚拟滚动时,高亮由js控制。如果仍想使用css 关键帧控制,则配置此项
|
|
118
129
|
*/
|
|
119
|
-
function setHighlightDimRow(rowKeyValues: UniqKey[], option: { useCss?: boolean } = {}) {
|
|
130
|
+
function setHighlightDimRow(rowKeyValues: UniqKey[], option: { useCss?: boolean; className?: string } = {}) {
|
|
120
131
|
if (!Array.isArray(rowKeyValues)) rowKeyValues = [rowKeyValues];
|
|
121
|
-
|
|
132
|
+
const { className, useCss } = { className: HIGHLIGHT_ROW_CLASS, useCss: false, ...option };
|
|
133
|
+
if (props.virtual && !useCss) {
|
|
122
134
|
// --------虚拟滚动用js计算颜色渐变的高亮方案
|
|
123
135
|
const nowTs = Date.now(); // 重置渐变进度
|
|
124
136
|
for (let i = 0; i < rowKeyValues.length; i++) {
|
|
@@ -141,8 +153,8 @@ export function useHighlight({ props, tableContainer }: Params) {
|
|
|
141
153
|
const rowKeyValue = rowKeyValues[i];
|
|
142
154
|
const rowEl = tableContainer.value?.querySelector<HTMLTableRowElement>(`[data-row-key="${rowKeyValue}"]`);
|
|
143
155
|
if (!rowEl) continue;
|
|
144
|
-
if (rowEl.classList.contains(
|
|
145
|
-
rowEl.classList.remove(
|
|
156
|
+
if (rowEl.classList.contains(className)) {
|
|
157
|
+
rowEl.classList.remove(className);
|
|
146
158
|
needRepaint = true;
|
|
147
159
|
}
|
|
148
160
|
rowElTemp.push(rowEl);
|
|
@@ -151,20 +163,21 @@ export function useHighlight({ props, tableContainer }: Params) {
|
|
|
151
163
|
highlightDimRowsTimeout.set(
|
|
152
164
|
rowKeyValue,
|
|
153
165
|
window.setTimeout(() => {
|
|
154
|
-
rowEl.classList.remove(
|
|
166
|
+
rowEl.classList.remove(className);
|
|
155
167
|
highlightDimRowsTimeout.delete(rowKeyValue); // 回收内存
|
|
156
|
-
},
|
|
168
|
+
}, duration),
|
|
157
169
|
);
|
|
158
170
|
}
|
|
159
171
|
if (needRepaint) {
|
|
160
172
|
void tableContainer.value?.offsetWidth; //强制浏览器重绘
|
|
161
173
|
}
|
|
162
|
-
rowElTemp.forEach(el => el.classList.add(
|
|
174
|
+
rowElTemp.forEach(el => el.classList.add(className)); // 统一添加动画
|
|
163
175
|
}
|
|
164
176
|
}
|
|
165
177
|
|
|
166
178
|
return {
|
|
167
179
|
highlightRowStore,
|
|
180
|
+
highlightFrom,
|
|
168
181
|
setHighlightDimRow,
|
|
169
182
|
setHighlightDimCell,
|
|
170
183
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Ref, ShallowRef, computed, ref } from 'vue';
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_TABLE_HEIGHT, DEFAULT_TABLE_WIDTH } from './const';
|
|
3
3
|
import { StkTableColumn } from './types';
|
|
4
4
|
import { getColWidth } from './utils';
|
|
5
5
|
|
|
@@ -145,7 +145,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
145
145
|
if (typeof height === 'number') {
|
|
146
146
|
containerHeight = height;
|
|
147
147
|
} else {
|
|
148
|
-
containerHeight = offsetHeight ||
|
|
148
|
+
containerHeight = offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
149
149
|
}
|
|
150
150
|
const { headless, headerRowHeight } = props;
|
|
151
151
|
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
@@ -162,7 +162,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
162
162
|
if (!props.virtualX) return;
|
|
163
163
|
const { offsetWidth, scrollLeft } = tableContainer.value || {};
|
|
164
164
|
// scrollTo(null, 0);
|
|
165
|
-
virtualScrollX.value.containerWidth = offsetWidth ||
|
|
165
|
+
virtualScrollX.value.containerWidth = offsetWidth || DEFAULT_TABLE_WIDTH;
|
|
166
166
|
updateVirtualScrollX(scrollLeft);
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
@@ -239,12 +239,16 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
239
239
|
let offsetLeft = 0;
|
|
240
240
|
|
|
241
241
|
let colWidthSum = 0;
|
|
242
|
+
let leftColWidthSum = 0;
|
|
242
243
|
for (let colIndex = 0; colIndex < headerLength; colIndex++) {
|
|
243
244
|
startIndex++;
|
|
244
245
|
const col = tableHeaderLast.value[colIndex];
|
|
245
|
-
// fixed left 不进入计算列宽
|
|
246
|
-
if (col.fixed === 'left') continue;
|
|
247
246
|
const colWidth = getColWidth(col);
|
|
247
|
+
// fixed left 不进入计算列宽
|
|
248
|
+
if (col.fixed === 'left') {
|
|
249
|
+
leftColWidthSum += colWidth;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
248
252
|
colWidthSum += colWidth;
|
|
249
253
|
// 列宽(非固定列)加到超过scrollLeft的时候,表示startIndex从上一个开始下标
|
|
250
254
|
if (colWidthSum >= sLeft) {
|
|
@@ -255,13 +259,14 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
255
259
|
}
|
|
256
260
|
// -----
|
|
257
261
|
colWidthSum = 0;
|
|
262
|
+
const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
|
|
258
263
|
let endIndex = headerLength;
|
|
259
264
|
for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
|
|
260
265
|
const col = tableHeaderLast.value[colIndex];
|
|
261
266
|
colWidthSum += getColWidth(col);
|
|
262
267
|
// 列宽大于容器宽度则停止
|
|
263
|
-
if (colWidthSum >=
|
|
264
|
-
endIndex = colIndex + 1; //
|
|
268
|
+
if (colWidthSum >= containerWidth) {
|
|
269
|
+
endIndex = colIndex + 1; // 由于slice[start,end),要加1
|
|
265
270
|
break;
|
|
266
271
|
}
|
|
267
272
|
}
|
package/src/StkTable/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEFAULT_COL_WIDTH } from './const';
|
|
2
2
|
import { Order, SortConfig, SortOption, SortState, StkTableColumn } from './types';
|
|
3
3
|
|
|
4
4
|
/** 是否空值 */
|
|
@@ -184,7 +184,7 @@ export function howDeepTheHeader(arr: StkTableColumn<any>[], level = 1) {
|
|
|
184
184
|
|
|
185
185
|
/** 获取列宽 */
|
|
186
186
|
export function getColWidth(col: StkTableColumn<any> | null): number {
|
|
187
|
-
const val = col?.width ??
|
|
187
|
+
const val = col?.width ?? DEFAULT_COL_WIDTH;
|
|
188
188
|
if (typeof val === 'number') {
|
|
189
189
|
return Math.floor(val);
|
|
190
190
|
}
|