stk-table-vue 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/lib/src/StkTable/StkTable.vue.d.ts +20 -20
- package/lib/src/StkTable/types/index.d.ts +12 -3
- package/lib/src/StkTable/useHighlight.d.ts +10 -3
- package/lib/src/StkTable/utils.d.ts +3 -1
- package/lib/stk-table-vue.js +56 -34
- package/package.json +1 -1
- package/src/StkTable/StkTable.vue +38 -21
- package/src/StkTable/types/index.ts +12 -3
- package/src/StkTable/useHighlight.ts +50 -33
- package/src/StkTable/utils.ts +20 -7
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@ Vue3 简易虚拟滚动表格。用于实时数据展示,新数据行高亮渐
|
|
|
5
5
|
Vue2.7支持引入源码(**ts**)使用。
|
|
6
6
|
|
|
7
7
|
## Bug TODO:
|
|
8
|
-
* [] props.dataSource 为 shallowRef 时,高亮行不生效。(2024.02.21)
|
|
8
|
+
* [x] props.dataSource 为 shallowRef 时,高亮行不生效。(bug:2024.02.21)(resolved:0.2.3)
|
|
9
|
+
|
|
9
10
|
## Feature TODO:
|
|
10
11
|
* [x] 高亮行,单元格。
|
|
11
12
|
* [x] 虚拟滚动。
|
|
@@ -22,7 +23,7 @@ Vue2.7支持引入源码(**ts**)使用。
|
|
|
22
23
|
* [x] 表头拖动调整列宽。
|
|
23
24
|
* [x] 排序
|
|
24
25
|
- [x] 基本表头点击排序。
|
|
25
|
-
- [] 支持配置 `null` | `undefined` 永远排最后。
|
|
26
|
+
- [x] 支持配置 `null` | `undefined` 永远排最后。
|
|
26
27
|
- [] 支持配置 string 使用 `String.prototype.localCompare` 排序。
|
|
27
28
|
* 多级表头。
|
|
28
29
|
- [x] 支持最多`2级`表头。
|
|
@@ -126,9 +127,9 @@ export type StkProps = {
|
|
|
126
127
|
/** 表格数据源 */
|
|
127
128
|
dataSource?: any[];
|
|
128
129
|
/** 行唯一键 */
|
|
129
|
-
rowKey?:
|
|
130
|
+
rowKey?: UniqKeyProp;
|
|
130
131
|
/** 列唯一键 */
|
|
131
|
-
colKey?:
|
|
132
|
+
colKey?: UniqKeyProp;
|
|
132
133
|
/** 空值展示文字 */
|
|
133
134
|
emptyCellText?: string;
|
|
134
135
|
/** 暂无数据兜底高度是否撑满 */
|
|
@@ -181,7 +182,12 @@ export type StkProps = {
|
|
|
181
182
|
/** 排序配置 */
|
|
182
183
|
sortConfig?: {
|
|
183
184
|
/** 空值是否排最下面 */
|
|
184
|
-
emptyToBottom:
|
|
185
|
+
emptyToBottom: boolean,
|
|
186
|
+
/** 默认排序(1.初始化时触发 2.排序方向为null时触发) */
|
|
187
|
+
defaultSort?: {
|
|
188
|
+
dataIndex: keyof T;
|
|
189
|
+
order: Order;
|
|
190
|
+
};
|
|
185
191
|
},
|
|
186
192
|
};
|
|
187
193
|
```
|
|
@@ -192,7 +198,7 @@ export type StkProps = {
|
|
|
192
198
|
* 排序变更触发
|
|
193
199
|
* ```(col: StkTableColumn<DT>, order: Order, data: DT[])```
|
|
194
200
|
*/
|
|
195
|
-
(e: 'sort-change', col: StkTableColumn<DT>, order: Order, data: DT[], sortConfig:SortConfig): void;
|
|
201
|
+
(e: 'sort-change', col: StkTableColumn<DT>, order: Order, data: DT[], sortConfig: SortConfig): void;
|
|
196
202
|
/**
|
|
197
203
|
* 一行点击事件
|
|
198
204
|
* ```(ev: MouseEvent, row: DT)```
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Order, SortConfig, SortOption, SortState, StkTableColumn,
|
|
1
|
+
import { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKeyProp } from './types/index';
|
|
2
2
|
/** Generic stands for DataType */
|
|
3
3
|
type DT = any;
|
|
4
4
|
/**
|
|
@@ -11,14 +11,14 @@ declare function setCurrentRow(rowKey: string, option?: {
|
|
|
11
11
|
}): void;
|
|
12
12
|
/**
|
|
13
13
|
* 设置表头排序状态
|
|
14
|
-
* @param
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
17
|
-
* @param
|
|
18
|
-
* @param
|
|
14
|
+
* @param dataIndex 列字段
|
|
15
|
+
* @param order 正序倒序
|
|
16
|
+
* @param option.sortOption 指定排序参数
|
|
17
|
+
* @param option.sort 是否触发排序-默认true
|
|
18
|
+
* @param option.silent 是否禁止触发回调-默认true
|
|
19
19
|
*/
|
|
20
|
-
declare function setSorter(dataIndex: string, order:
|
|
21
|
-
sortOption?: SortOption
|
|
20
|
+
declare function setSorter(dataIndex: string, order: Order, option?: {
|
|
21
|
+
sortOption?: SortOption<DT>;
|
|
22
22
|
silent?: boolean;
|
|
23
23
|
sort?: boolean;
|
|
24
24
|
}): any[];
|
|
@@ -61,9 +61,9 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
61
61
|
/** 表格数据源 */
|
|
62
62
|
dataSource?: any[] | undefined;
|
|
63
63
|
/** 行唯一键 */
|
|
64
|
-
rowKey?:
|
|
64
|
+
rowKey?: UniqKeyProp | undefined;
|
|
65
65
|
/** 列唯一键 */
|
|
66
|
-
colKey?:
|
|
66
|
+
colKey?: UniqKeyProp | undefined;
|
|
67
67
|
/** 空值展示文字 */
|
|
68
68
|
emptyCellText?: string | undefined;
|
|
69
69
|
/** 暂无数据兜底高度是否撑满 */
|
|
@@ -112,7 +112,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
112
112
|
/** 优化vue2 滚动 */
|
|
113
113
|
optimizeVue2Scroll?: boolean | undefined;
|
|
114
114
|
/** 排序配置 */
|
|
115
|
-
sortConfig?: SortConfig | undefined;
|
|
115
|
+
sortConfig?: SortConfig<any> | undefined;
|
|
116
116
|
}>, {
|
|
117
117
|
width: string;
|
|
118
118
|
fixedMode: boolean;
|
|
@@ -159,7 +159,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
159
159
|
/** 设置高亮渐暗单元格 */
|
|
160
160
|
setHighlightDimCell: (rowKeyValue: string, dataIndex: string) => void;
|
|
161
161
|
/** 设置高亮渐暗行 */
|
|
162
|
-
setHighlightDimRow: (rowKeyValues: (
|
|
162
|
+
setHighlightDimRow: (rowKeyValues: import("./types/index").UniqKey[]) => void;
|
|
163
163
|
/** 表格排序列dataIndex */
|
|
164
164
|
sortCol: import("vue").Ref<string | null | undefined>;
|
|
165
165
|
/** 获取当前排序状态 */
|
|
@@ -173,7 +173,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
173
173
|
/** 获取表格数据 */
|
|
174
174
|
getTableData: typeof getTableData;
|
|
175
175
|
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
176
|
-
"sort-change": (col: StkTableColumn<any>, order: Order, data: any[], sortConfig: SortConfig) => void;
|
|
176
|
+
"sort-change": (col: StkTableColumn<any>, order: Order, data: any[], sortConfig: SortConfig<any>) => void;
|
|
177
177
|
"row-click": (ev: MouseEvent, row: any) => void;
|
|
178
178
|
"current-change": (ev: MouseEvent | null, row: any) => void;
|
|
179
179
|
"row-dblclick": (ev: MouseEvent, row: any) => void;
|
|
@@ -217,9 +217,9 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
217
217
|
/** 表格数据源 */
|
|
218
218
|
dataSource?: any[] | undefined;
|
|
219
219
|
/** 行唯一键 */
|
|
220
|
-
rowKey?:
|
|
220
|
+
rowKey?: UniqKeyProp | undefined;
|
|
221
221
|
/** 列唯一键 */
|
|
222
|
-
colKey?:
|
|
222
|
+
colKey?: UniqKeyProp | undefined;
|
|
223
223
|
/** 空值展示文字 */
|
|
224
224
|
emptyCellText?: string | undefined;
|
|
225
225
|
/** 暂无数据兜底高度是否撑满 */
|
|
@@ -268,7 +268,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
268
268
|
/** 优化vue2 滚动 */
|
|
269
269
|
optimizeVue2Scroll?: boolean | undefined;
|
|
270
270
|
/** 排序配置 */
|
|
271
|
-
sortConfig?: SortConfig | undefined;
|
|
271
|
+
sortConfig?: SortConfig<any> | undefined;
|
|
272
272
|
}>, {
|
|
273
273
|
width: string;
|
|
274
274
|
fixedMode: boolean;
|
|
@@ -312,7 +312,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
312
312
|
"onTh-drag-start"?: ((dragStartKey: string) => any) | undefined;
|
|
313
313
|
"onCol-order-change"?: ((dragStartKey: string, targetColKey: string) => any) | undefined;
|
|
314
314
|
"onTh-drop"?: ((targetColKey: string) => any) | undefined;
|
|
315
|
-
"onSort-change"?: ((col: StkTableColumn<any>, order: Order, data: any[], sortConfig: SortConfig) => any) | undefined;
|
|
315
|
+
"onSort-change"?: ((col: StkTableColumn<any>, order: Order, data: any[], sortConfig: SortConfig<any>) => any) | undefined;
|
|
316
316
|
"onRow-click"?: ((ev: MouseEvent, row: any) => any) | undefined;
|
|
317
317
|
"onCurrent-change"?: ((ev: MouseEvent | null, row: any) => any) | undefined;
|
|
318
318
|
"onRow-dblclick"?: ((ev: MouseEvent, row: any) => any) | undefined;
|
|
@@ -335,8 +335,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
335
335
|
virtualX: boolean;
|
|
336
336
|
columns: StkTableColumn<any>[];
|
|
337
337
|
dataSource: any[];
|
|
338
|
-
rowKey:
|
|
339
|
-
colKey:
|
|
338
|
+
rowKey: UniqKeyProp;
|
|
339
|
+
colKey: UniqKeyProp;
|
|
340
340
|
emptyCellText: string;
|
|
341
341
|
noDataFull: boolean;
|
|
342
342
|
showNoData: boolean;
|
|
@@ -352,7 +352,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
352
352
|
autoResize: boolean | (() => void);
|
|
353
353
|
fixedColShadow: boolean;
|
|
354
354
|
optimizeVue2Scroll: boolean;
|
|
355
|
-
sortConfig: SortConfig
|
|
355
|
+
sortConfig: SortConfig<any>;
|
|
356
356
|
}, {}>, {
|
|
357
357
|
tableHeader?(_: {
|
|
358
358
|
col: StkTableColumn<any>;
|
|
@@ -63,16 +63,25 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
63
63
|
/** 父节点引用 */
|
|
64
64
|
__PARENT__?: StkTableColumn<T> | null;
|
|
65
65
|
};
|
|
66
|
-
export type SortOption = Pick<StkTableColumn<
|
|
66
|
+
export type SortOption<T extends Record<string, any>> = Pick<StkTableColumn<T>, 'sorter' | 'dataIndex' | 'sortField' | 'sortType'>;
|
|
67
|
+
/** 排序状态 */
|
|
67
68
|
export type SortState<T> = {
|
|
68
69
|
dataIndex: T;
|
|
69
70
|
order: null | 'asc' | 'desc';
|
|
70
71
|
sortType?: 'number' | 'string';
|
|
71
72
|
};
|
|
72
|
-
|
|
73
|
+
/** 唯一键 */
|
|
74
|
+
export type UniqKey = string | number;
|
|
75
|
+
export type UniqKeyFun = (param: any) => UniqKey;
|
|
76
|
+
export type UniqKeyProp = UniqKey | UniqKeyFun;
|
|
73
77
|
/** 排序配置 */
|
|
74
|
-
export type SortConfig = {
|
|
78
|
+
export type SortConfig<T extends Record<string, any>> = {
|
|
75
79
|
/** 空值始终排在列表末尾 */
|
|
76
80
|
emptyToBottom?: boolean;
|
|
81
|
+
/** 默认排序(1.初始化时触发 2.排序方向为null时触发) */
|
|
82
|
+
defaultSort?: {
|
|
83
|
+
dataIndex: keyof T;
|
|
84
|
+
order: Order;
|
|
85
|
+
};
|
|
77
86
|
};
|
|
78
87
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Ref } from 'vue';
|
|
2
|
+
import { UniqKey } from './types';
|
|
2
3
|
type Params = {
|
|
3
4
|
props: {
|
|
4
5
|
theme: 'light' | 'dark';
|
|
@@ -6,14 +7,20 @@ type Params = {
|
|
|
6
7
|
dataSource: any[];
|
|
7
8
|
};
|
|
8
9
|
tableContainer: Ref<HTMLElement | undefined>;
|
|
9
|
-
|
|
10
|
+
};
|
|
11
|
+
/** 高亮行保存的东西 */
|
|
12
|
+
type HighlightRowStore = {
|
|
13
|
+
bgc: string;
|
|
14
|
+
bgc_progress_ms: number;
|
|
15
|
+
bgc_progress: number;
|
|
10
16
|
};
|
|
11
17
|
/**
|
|
12
18
|
* 高亮单元格,行
|
|
13
19
|
* row中新增_bgc_progress_ms 属性控制高亮状态,_bgc控制颜色
|
|
14
20
|
*/
|
|
15
|
-
export declare function useHighlight({ props, tableContainer
|
|
16
|
-
|
|
21
|
+
export declare function useHighlight({ props, tableContainer }: Params): {
|
|
22
|
+
highlightRowStore: Ref<Record<UniqKey, HighlightRowStore>>;
|
|
23
|
+
setHighlightDimRow: (rowKeyValues: UniqKey[]) => void;
|
|
17
24
|
setHighlightDimCell: (rowKeyValue: string, dataIndex: string) => void;
|
|
18
25
|
};
|
|
19
26
|
export {};
|
|
@@ -14,11 +14,13 @@ export declare function insertToOrderedArray<T extends object>(sortState: SortSt
|
|
|
14
14
|
* 可以在组件外部自己实现表格排序,组件配置remote,使表格不排序。
|
|
15
15
|
* 使用者在@sort-change事件中自行更改table props 'dataSource'完成排序。
|
|
16
16
|
* TODO: key 唯一值,排序字段相同时,根据唯一值排序。
|
|
17
|
+
*
|
|
18
|
+
* sortConfig.defaultSort 会在order为null时生效
|
|
17
19
|
* @param sortOption 列配置
|
|
18
20
|
* @param order 排序方式
|
|
19
21
|
* @param dataSource 排序的数组
|
|
20
22
|
*/
|
|
21
|
-
export declare function tableSort(sortOption: SortOption
|
|
23
|
+
export declare function tableSort<T extends Record<string, any>>(sortOption: SortOption<T>, order: Order, dataSource: T[], sortConfig?: SortConfig<T>): T[];
|
|
22
24
|
/** 表头column配置的层级 */
|
|
23
25
|
export declare function howDeepTheHeader(arr: StkTableColumn<any>[], level?: number): number;
|
|
24
26
|
/** 获取列宽 */
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -138,14 +138,18 @@ function separatedData(sortOption, targetDataSource, isNumber) {
|
|
|
138
138
|
function tableSort(sortOption, order, dataSource, sortConfig = {}) {
|
|
139
139
|
if (!(dataSource == null ? void 0 : dataSource.length))
|
|
140
140
|
return dataSource || [];
|
|
141
|
-
sortConfig =
|
|
141
|
+
sortConfig = { emptyToBottom: false, ...sortConfig };
|
|
142
142
|
let targetDataSource = [...dataSource];
|
|
143
|
+
let sortField = sortOption.sortField || sortOption.dataIndex;
|
|
144
|
+
if (!order && sortConfig.defaultSort) {
|
|
145
|
+
order = sortConfig.defaultSort.order;
|
|
146
|
+
sortField = sortConfig.defaultSort.dataIndex;
|
|
147
|
+
}
|
|
143
148
|
if (typeof sortOption.sorter === "function") {
|
|
144
149
|
const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });
|
|
145
150
|
if (customSorterData)
|
|
146
151
|
targetDataSource = customSorterData;
|
|
147
152
|
} else if (order) {
|
|
148
|
-
const sortField = sortOption.sortField || sortOption.dataIndex;
|
|
149
153
|
let { sortType } = sortOption;
|
|
150
154
|
if (!sortType)
|
|
151
155
|
sortType = typeof dataSource[0][sortField];
|
|
@@ -436,11 +440,14 @@ function useFixedStyle({ props, tableHeaderLast, virtualScroll, virtualScrollX,
|
|
|
436
440
|
getFixedStyle
|
|
437
441
|
};
|
|
438
442
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
});
|
|
443
|
-
const
|
|
443
|
+
const HIGHLIGHT_ROW_CLASS = "highlight-row";
|
|
444
|
+
const HIGHLIGHT_CELL_CLASS = "highlight-cell";
|
|
445
|
+
function useHighlight({ props, tableContainer }) {
|
|
446
|
+
const highlightRowStore = ref({});
|
|
447
|
+
const highlightFrom = Highlight_Color[props.theme].from;
|
|
448
|
+
const highlightTo = Highlight_Color[props.theme].to;
|
|
449
|
+
const highlightInter = computed(() => interpolateRgb(highlightFrom, highlightTo));
|
|
450
|
+
const highlightDimRowKeys = /* @__PURE__ */ new Set();
|
|
444
451
|
const highlightDimRowsTimeout = /* @__PURE__ */ new Map();
|
|
445
452
|
const highlightDimCellsTimeout = /* @__PURE__ */ new Map();
|
|
446
453
|
let calcHighlightDimLoop = false;
|
|
@@ -451,18 +458,17 @@ function useHighlight({ props, tableContainer, rowKeyGen }) {
|
|
|
451
458
|
const recursion = () => {
|
|
452
459
|
window.setTimeout(() => {
|
|
453
460
|
const nowTs = Date.now();
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const progress = (nowTs -
|
|
461
|
+
highlightDimRowKeys.forEach((rowKeyValue) => {
|
|
462
|
+
const highlightItem = highlightRowStore.value[rowKeyValue];
|
|
463
|
+
const progress = (nowTs - highlightItem.bgc_progress_ms) / Highlight_Duration;
|
|
457
464
|
if (0 < progress && progress < 1) {
|
|
458
|
-
|
|
465
|
+
highlightItem.bgc = highlightInter.value(progress);
|
|
459
466
|
} else {
|
|
460
|
-
|
|
461
|
-
|
|
467
|
+
highlightItem.bgc = "";
|
|
468
|
+
highlightDimRowKeys.delete(rowKeyValue);
|
|
462
469
|
}
|
|
463
470
|
});
|
|
464
|
-
|
|
465
|
-
if (highlightDimRows.size > 0) {
|
|
471
|
+
if (highlightDimRowKeys.size > 0) {
|
|
466
472
|
recursion();
|
|
467
473
|
} else {
|
|
468
474
|
calcHighlightDimLoop = false;
|
|
@@ -476,16 +482,16 @@ function useHighlight({ props, tableContainer, rowKeyGen }) {
|
|
|
476
482
|
const cellEl = (_a = tableContainer.value) == null ? void 0 : _a.querySelector(`[data-row-key="${rowKeyValue}"]>[data-index="${dataIndex}"]`);
|
|
477
483
|
if (!cellEl)
|
|
478
484
|
return;
|
|
479
|
-
if (cellEl.classList.contains(
|
|
480
|
-
cellEl.classList.remove(
|
|
485
|
+
if (cellEl.classList.contains(HIGHLIGHT_CELL_CLASS)) {
|
|
486
|
+
cellEl.classList.remove(HIGHLIGHT_CELL_CLASS);
|
|
481
487
|
void cellEl.offsetHeight;
|
|
482
488
|
}
|
|
483
|
-
cellEl.classList.add(
|
|
489
|
+
cellEl.classList.add(HIGHLIGHT_CELL_CLASS);
|
|
484
490
|
window.clearTimeout(highlightDimCellsTimeout.get(rowKeyValue));
|
|
485
491
|
highlightDimCellsTimeout.set(
|
|
486
492
|
rowKeyValue,
|
|
487
493
|
window.setTimeout(() => {
|
|
488
|
-
cellEl.classList.remove(
|
|
494
|
+
cellEl.classList.remove(HIGHLIGHT_CELL_CLASS);
|
|
489
495
|
highlightDimCellsTimeout.delete(rowKeyValue);
|
|
490
496
|
}, Highlight_Duration)
|
|
491
497
|
);
|
|
@@ -498,11 +504,12 @@ function useHighlight({ props, tableContainer, rowKeyGen }) {
|
|
|
498
504
|
const nowTs = Date.now();
|
|
499
505
|
for (let i = 0; i < rowKeyValues.length; i++) {
|
|
500
506
|
const rowKeyValue = rowKeyValues[i];
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
507
|
+
highlightRowStore.value[rowKeyValue] = {
|
|
508
|
+
bgc: "",
|
|
509
|
+
bgc_progress: 0,
|
|
510
|
+
bgc_progress_ms: nowTs
|
|
511
|
+
};
|
|
512
|
+
highlightDimRowKeys.add(rowKeyValue);
|
|
506
513
|
}
|
|
507
514
|
calcHighlightLoop();
|
|
508
515
|
} else {
|
|
@@ -513,8 +520,8 @@ function useHighlight({ props, tableContainer, rowKeyGen }) {
|
|
|
513
520
|
const rowEl = (_a = tableContainer.value) == null ? void 0 : _a.querySelector(`[data-row-key="${rowKeyValue}"]`);
|
|
514
521
|
if (!rowEl)
|
|
515
522
|
continue;
|
|
516
|
-
if (rowEl.classList.contains(
|
|
517
|
-
rowEl.classList.remove(
|
|
523
|
+
if (rowEl.classList.contains(HIGHLIGHT_ROW_CLASS)) {
|
|
524
|
+
rowEl.classList.remove(HIGHLIGHT_ROW_CLASS);
|
|
518
525
|
needRepaint = true;
|
|
519
526
|
}
|
|
520
527
|
rowElTemp.push(rowEl);
|
|
@@ -522,7 +529,7 @@ function useHighlight({ props, tableContainer, rowKeyGen }) {
|
|
|
522
529
|
highlightDimRowsTimeout.set(
|
|
523
530
|
rowKeyValue,
|
|
524
531
|
window.setTimeout(() => {
|
|
525
|
-
rowEl.classList.remove(
|
|
532
|
+
rowEl.classList.remove(HIGHLIGHT_ROW_CLASS);
|
|
526
533
|
highlightDimRowsTimeout.delete(rowKeyValue);
|
|
527
534
|
}, Highlight_Duration)
|
|
528
535
|
);
|
|
@@ -530,10 +537,11 @@ function useHighlight({ props, tableContainer, rowKeyGen }) {
|
|
|
530
537
|
if (needRepaint) {
|
|
531
538
|
void ((_b = tableContainer.value) == null ? void 0 : _b.offsetWidth);
|
|
532
539
|
}
|
|
533
|
-
rowElTemp.forEach((el) => el.classList.add(
|
|
540
|
+
rowElTemp.forEach((el) => el.classList.add(HIGHLIGHT_ROW_CLASS));
|
|
534
541
|
}
|
|
535
542
|
}
|
|
536
543
|
return {
|
|
544
|
+
highlightRowStore,
|
|
537
545
|
setHighlightDimRow,
|
|
538
546
|
setHighlightDimCell
|
|
539
547
|
};
|
|
@@ -887,8 +895,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
887
895
|
virtualX: { type: Boolean, default: false },
|
|
888
896
|
columns: { default: () => [] },
|
|
889
897
|
dataSource: { default: () => [] },
|
|
890
|
-
rowKey: { type: [String, Function], default: "" },
|
|
891
|
-
colKey: { type: [String, Function], default: "dataIndex" },
|
|
898
|
+
rowKey: { type: [String, Number, Function], default: "" },
|
|
899
|
+
colKey: { type: [String, Number, Function], default: "dataIndex" },
|
|
892
900
|
emptyCellText: { default: "--" },
|
|
893
901
|
noDataFull: { type: Boolean, default: false },
|
|
894
902
|
showNoData: { type: Boolean, default: true },
|
|
@@ -956,7 +964,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
956
964
|
virtualX_on,
|
|
957
965
|
virtualX_offsetRight
|
|
958
966
|
});
|
|
959
|
-
const { setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer
|
|
967
|
+
const { highlightRowStore, setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer });
|
|
960
968
|
if (props.autoResize) {
|
|
961
969
|
useAutoResize({ tableContainer, initVirtualScroll, props, debounceMs: 200 });
|
|
962
970
|
}
|
|
@@ -1008,7 +1016,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1008
1016
|
onMounted(() => {
|
|
1009
1017
|
initVirtualScroll();
|
|
1010
1018
|
updateFixedShadow();
|
|
1019
|
+
dealDefaultSorter();
|
|
1011
1020
|
});
|
|
1021
|
+
function dealDefaultSorter() {
|
|
1022
|
+
if (!props.sortConfig.defaultSort)
|
|
1023
|
+
return;
|
|
1024
|
+
const { dataIndex, order } = props.sortConfig.defaultSort;
|
|
1025
|
+
setSorter(dataIndex, order);
|
|
1026
|
+
}
|
|
1012
1027
|
function dealColumns() {
|
|
1013
1028
|
tableHeaders.value = [];
|
|
1014
1029
|
tableHeaderLast.value = [];
|
|
@@ -1104,8 +1119,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1104
1119
|
if (click)
|
|
1105
1120
|
sortOrderIndex.value++;
|
|
1106
1121
|
sortOrderIndex.value = sortOrderIndex.value % 3;
|
|
1107
|
-
|
|
1122
|
+
let order = sortSwitchOrder[sortOrderIndex.value];
|
|
1108
1123
|
const sortConfig = props.sortConfig;
|
|
1124
|
+
const defaultSort = sortConfig.defaultSort;
|
|
1125
|
+
if (!order && defaultSort) {
|
|
1126
|
+
order = defaultSort.order;
|
|
1127
|
+
sortOrderIndex.value = sortSwitchOrder.indexOf(order);
|
|
1128
|
+
sortCol.value = defaultSort.dataIndex;
|
|
1129
|
+
}
|
|
1109
1130
|
if (!props.sortRemote || options.force) {
|
|
1110
1131
|
dataSourceCopy.value = tableSort(col, order, props.dataSource, sortConfig);
|
|
1111
1132
|
}
|
|
@@ -1189,7 +1210,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1189
1210
|
var _a;
|
|
1190
1211
|
const newOption = { silent: true, sortOption: null, sort: true, ...option };
|
|
1191
1212
|
sortCol.value = dataIndex;
|
|
1192
|
-
sortOrderIndex.value = sortSwitchOrder.
|
|
1213
|
+
sortOrderIndex.value = sortSwitchOrder.indexOf(order);
|
|
1193
1214
|
if (newOption.sort && ((_a = dataSourceCopy.value) == null ? void 0 : _a.length)) {
|
|
1194
1215
|
const column = newOption.sortOption || tableHeaderLast.value.find((it) => it.dataIndex === sortCol.value);
|
|
1195
1216
|
if (column)
|
|
@@ -1377,6 +1398,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1377
1398
|
}), 128)) : createCommentVNode("", true)
|
|
1378
1399
|
], 4)) : createCommentVNode("", true),
|
|
1379
1400
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtual_dataSourcePart), (row, i) => {
|
|
1401
|
+
var _a;
|
|
1380
1402
|
return openBlock(), createElementBlock("tr", {
|
|
1381
1403
|
key: _ctx.rowKey ? rowKeyGen(row) : i,
|
|
1382
1404
|
"data-row-key": _ctx.rowKey ? rowKeyGen(row) : i,
|
|
@@ -1386,7 +1408,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1386
1408
|
[_ctx.rowClassName(row, i)]: true
|
|
1387
1409
|
}),
|
|
1388
1410
|
style: normalizeStyle({
|
|
1389
|
-
backgroundColor: row.
|
|
1411
|
+
backgroundColor: (_a = unref(highlightRowStore)[rowKeyGen(row)]) == null ? void 0 : _a.bgc
|
|
1390
1412
|
}),
|
|
1391
1413
|
onClick: (e) => onRowClick(e, row),
|
|
1392
1414
|
onDblclick: (e) => onRowDblclick(e, row),
|
package/package.json
CHANGED
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
[rowClassName(row, i)]: true,
|
|
149
149
|
}"
|
|
150
150
|
:style="{
|
|
151
|
-
backgroundColor: row
|
|
151
|
+
backgroundColor: highlightRowStore[rowKeyGen(row)]?.bgc,
|
|
152
152
|
}"
|
|
153
153
|
@click="e => onRowClick(e, row)"
|
|
154
154
|
@dblclick="e => onRowDblclick(e, row)"
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
*/
|
|
192
192
|
import { CSSProperties, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
|
|
193
193
|
import { Default_Row_Height } from './const';
|
|
194
|
-
import { Order, SortConfig, SortOption, SortState, StkTableColumn,
|
|
194
|
+
import { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKeyProp } from './types/index';
|
|
195
195
|
import { useAutoResize } from './useAutoResize';
|
|
196
196
|
import { useColResize } from './useColResize';
|
|
197
197
|
import { useFixedCol } from './useFixedCol';
|
|
@@ -235,9 +235,9 @@ const props = withDefaults(
|
|
|
235
235
|
/** 表格数据源 */
|
|
236
236
|
dataSource?: DT[];
|
|
237
237
|
/** 行唯一键 */
|
|
238
|
-
rowKey?:
|
|
238
|
+
rowKey?: UniqKeyProp;
|
|
239
239
|
/** 列唯一键 */
|
|
240
|
-
colKey?:
|
|
240
|
+
colKey?: UniqKeyProp;
|
|
241
241
|
/** 空值展示文字 */
|
|
242
242
|
emptyCellText?: string;
|
|
243
243
|
/** 暂无数据兜底高度是否撑满 */
|
|
@@ -286,7 +286,7 @@ const props = withDefaults(
|
|
|
286
286
|
/** 优化vue2 滚动 */
|
|
287
287
|
optimizeVue2Scroll?: boolean;
|
|
288
288
|
/** 排序配置 */
|
|
289
|
-
sortConfig?: SortConfig
|
|
289
|
+
sortConfig?: SortConfig<DT>;
|
|
290
290
|
}>(),
|
|
291
291
|
{
|
|
292
292
|
width: '',
|
|
@@ -330,7 +330,7 @@ const emits = defineEmits<{
|
|
|
330
330
|
* 排序变更触发
|
|
331
331
|
* ```(col: StkTableColumn<DT>, order: Order, data: DT[])```
|
|
332
332
|
*/
|
|
333
|
-
(e: 'sort-change', col: StkTableColumn<DT>, order: Order, data: DT[], sortConfig: SortConfig): void;
|
|
333
|
+
(e: 'sort-change', col: StkTableColumn<DT>, order: Order, data: DT[], sortConfig: SortConfig<DT>): void;
|
|
334
334
|
/**
|
|
335
335
|
* 一行点击事件
|
|
336
336
|
* ```(ev: MouseEvent, row: DT)```
|
|
@@ -484,7 +484,7 @@ const { getFixedStyle } = useFixedStyle({
|
|
|
484
484
|
/**
|
|
485
485
|
* 高亮行,高亮单元格
|
|
486
486
|
*/
|
|
487
|
-
const { setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer
|
|
487
|
+
const { highlightRowStore, setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, tableContainer });
|
|
488
488
|
|
|
489
489
|
if (props.autoResize) {
|
|
490
490
|
useAutoResize({ tableContainer, initVirtualScroll, props, debounceMs: 200 });
|
|
@@ -548,8 +548,16 @@ watch(() => props.fixedColShadow, dealFixedColShadow);
|
|
|
548
548
|
onMounted(() => {
|
|
549
549
|
initVirtualScroll();
|
|
550
550
|
updateFixedShadow();
|
|
551
|
+
dealDefaultSorter();
|
|
551
552
|
});
|
|
552
553
|
|
|
554
|
+
/** 处理默认排序 */
|
|
555
|
+
function dealDefaultSorter() {
|
|
556
|
+
if (!props.sortConfig.defaultSort) return;
|
|
557
|
+
const { dataIndex, order } = props.sortConfig.defaultSort;
|
|
558
|
+
setSorter(dataIndex as string, order);
|
|
559
|
+
}
|
|
560
|
+
|
|
553
561
|
/**
|
|
554
562
|
* 处理多级表头
|
|
555
563
|
*/
|
|
@@ -559,7 +567,7 @@ function dealColumns() {
|
|
|
559
567
|
tableHeaderLast.value = [];
|
|
560
568
|
const copyColumn = props.columns; // do not deep clone
|
|
561
569
|
const deep = howDeepTheHeader(copyColumn);
|
|
562
|
-
const tempHeaderLast: StkTableColumn<
|
|
570
|
+
const tempHeaderLast: StkTableColumn<DT>[] = [];
|
|
563
571
|
|
|
564
572
|
if (deep > 1 && props.virtualX) {
|
|
565
573
|
console.error('多级表头不支持横向虚拟滚动');
|
|
@@ -637,7 +645,7 @@ function colKeyGen(col: StkTableColumn<DT>) {
|
|
|
637
645
|
}
|
|
638
646
|
|
|
639
647
|
/** 获取列宽度样式 */
|
|
640
|
-
function getColWidthStyle(col: StkTableColumn<
|
|
648
|
+
function getColWidthStyle(col: StkTableColumn<DT>) {
|
|
641
649
|
const style: CSSProperties = {
|
|
642
650
|
width: col.width,
|
|
643
651
|
minWidth: col.minWidth,
|
|
@@ -662,7 +670,7 @@ function getColWidthStyle(col: StkTableColumn<any>) {
|
|
|
662
670
|
* @param col
|
|
663
671
|
* @param depth 表头层级
|
|
664
672
|
*/
|
|
665
|
-
function getCellStyle(tagType: 1 | 2, col: StkTableColumn<
|
|
673
|
+
function getCellStyle(tagType: 1 | 2, col: StkTableColumn<DT>, depth?: number): CSSProperties {
|
|
666
674
|
const style: CSSProperties = {
|
|
667
675
|
...getColWidthStyle(col),
|
|
668
676
|
...getFixedStyle(tagType, col, depth),
|
|
@@ -680,10 +688,11 @@ function getCellStyle(tagType: 1 | 2, col: StkTableColumn<any>, depth?: number):
|
|
|
680
688
|
|
|
681
689
|
/**
|
|
682
690
|
* 表头点击排序
|
|
683
|
-
* @param
|
|
684
|
-
* @param
|
|
691
|
+
* @param click 是否为点击表头触发
|
|
692
|
+
* @param options.force sort-remote 开启后是否强制排序
|
|
693
|
+
* @param options.emit 是否触发回调
|
|
685
694
|
*/
|
|
686
|
-
function onColumnSort(col?: StkTableColumn<
|
|
695
|
+
function onColumnSort(col?: StkTableColumn<DT>, click = true, options: { force?: boolean; emit?: boolean } = {}) {
|
|
687
696
|
if (!col?.sorter) return;
|
|
688
697
|
options = { force: false, emit: false, ...options };
|
|
689
698
|
if (sortCol.value !== col.dataIndex) {
|
|
@@ -694,8 +703,16 @@ function onColumnSort(col?: StkTableColumn<any>, click = true, options: { force?
|
|
|
694
703
|
if (click) sortOrderIndex.value++;
|
|
695
704
|
sortOrderIndex.value = sortOrderIndex.value % 3;
|
|
696
705
|
|
|
697
|
-
|
|
706
|
+
let order = sortSwitchOrder[sortOrderIndex.value];
|
|
698
707
|
const sortConfig = props.sortConfig;
|
|
708
|
+
const defaultSort = sortConfig.defaultSort;
|
|
709
|
+
|
|
710
|
+
if (!order && defaultSort) {
|
|
711
|
+
// 没有排序时变成默认排序
|
|
712
|
+
order = defaultSort.order;
|
|
713
|
+
sortOrderIndex.value = sortSwitchOrder.indexOf(order);
|
|
714
|
+
sortCol.value = defaultSort.dataIndex as string;
|
|
715
|
+
}
|
|
699
716
|
if (!props.sortRemote || options.force) {
|
|
700
717
|
dataSourceCopy.value = tableSort(col, order, props.dataSource, sortConfig);
|
|
701
718
|
}
|
|
@@ -813,16 +830,16 @@ function setCurrentRow(rowKey: string, option = { silent: false }) {
|
|
|
813
830
|
|
|
814
831
|
/**
|
|
815
832
|
* 设置表头排序状态
|
|
816
|
-
* @param
|
|
817
|
-
* @param
|
|
818
|
-
* @param
|
|
819
|
-
* @param
|
|
820
|
-
* @param
|
|
833
|
+
* @param dataIndex 列字段
|
|
834
|
+
* @param order 正序倒序
|
|
835
|
+
* @param option.sortOption 指定排序参数
|
|
836
|
+
* @param option.sort 是否触发排序-默认true
|
|
837
|
+
* @param option.silent 是否禁止触发回调-默认true
|
|
821
838
|
*/
|
|
822
|
-
function setSorter(dataIndex: string, order:
|
|
839
|
+
function setSorter(dataIndex: string, order: Order, option: { sortOption?: SortOption<DT>; silent?: boolean; sort?: boolean } = {}) {
|
|
823
840
|
const newOption = { silent: true, sortOption: null, sort: true, ...option };
|
|
824
841
|
sortCol.value = dataIndex;
|
|
825
|
-
sortOrderIndex.value = sortSwitchOrder.
|
|
842
|
+
sortOrderIndex.value = sortSwitchOrder.indexOf(order);
|
|
826
843
|
|
|
827
844
|
if (newOption.sort && dataSourceCopy.value?.length) {
|
|
828
845
|
// 如果表格有数据,则进行排序
|
|
@@ -59,18 +59,27 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
59
59
|
__PARENT__?: StkTableColumn<T> | null;
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
export type SortOption = Pick<StkTableColumn<
|
|
62
|
+
export type SortOption<T extends Record<string, any>> = Pick<StkTableColumn<T>, 'sorter' | 'dataIndex' | 'sortField' | 'sortType'>;
|
|
63
63
|
|
|
64
|
+
/** 排序状态 */
|
|
64
65
|
export type SortState<T> = {
|
|
65
66
|
dataIndex: T;
|
|
66
67
|
order: null | 'asc' | 'desc';
|
|
67
68
|
sortType?: 'number' | 'string';
|
|
68
69
|
};
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
/** 唯一键 */
|
|
72
|
+
export type UniqKey = string | number;
|
|
73
|
+
export type UniqKeyFun = (param: any) => UniqKey;
|
|
74
|
+
export type UniqKeyProp = UniqKey | UniqKeyFun;
|
|
71
75
|
|
|
72
76
|
/** 排序配置 */
|
|
73
|
-
export type SortConfig = {
|
|
77
|
+
export type SortConfig<T extends Record<string, any>> = {
|
|
74
78
|
/** 空值始终排在列表末尾 */
|
|
75
79
|
emptyToBottom?: boolean;
|
|
80
|
+
/** 默认排序(1.初始化时触发 2.排序方向为null时触发) */
|
|
81
|
+
defaultSort?: {
|
|
82
|
+
dataIndex: keyof T;
|
|
83
|
+
order: Order;
|
|
84
|
+
};
|
|
76
85
|
};
|
|
@@ -1,22 +1,41 @@
|
|
|
1
1
|
import { interpolateRgb } from 'd3-interpolate';
|
|
2
|
-
import { Ref, computed } from 'vue';
|
|
2
|
+
import { Ref, computed, ref } from 'vue';
|
|
3
3
|
import { Highlight_Color, Highlight_Color_Change_Freq, Highlight_Duration } from './const';
|
|
4
|
+
import { UniqKey } from './types';
|
|
4
5
|
|
|
5
6
|
type Params = {
|
|
6
7
|
props: { theme: 'light' | 'dark'; virtual: boolean; dataSource: any[] };
|
|
7
8
|
tableContainer: Ref<HTMLElement | undefined>;
|
|
8
|
-
rowKeyGen: (p: any) => string;
|
|
9
9
|
};
|
|
10
|
+
|
|
11
|
+
/** 高亮行保存的东西 */
|
|
12
|
+
type HighlightRowStore = {
|
|
13
|
+
bgc: string;
|
|
14
|
+
bgc_progress_ms: number;
|
|
15
|
+
bgc_progress: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** 高亮行class */
|
|
19
|
+
const HIGHLIGHT_ROW_CLASS = 'highlight-row';
|
|
20
|
+
/** 高连单元格class */
|
|
21
|
+
const HIGHLIGHT_CELL_CLASS = 'highlight-cell';
|
|
22
|
+
|
|
10
23
|
/**
|
|
11
24
|
* 高亮单元格,行
|
|
12
25
|
* row中新增_bgc_progress_ms 属性控制高亮状态,_bgc控制颜色
|
|
13
26
|
*/
|
|
14
|
-
export function useHighlight({ props, tableContainer
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
export function useHighlight({ props, tableContainer }: Params) {
|
|
28
|
+
/**
|
|
29
|
+
* 高亮行记录 key-rowKey, value-obj
|
|
30
|
+
*/
|
|
31
|
+
const highlightRowStore = ref<Record<UniqKey, HighlightRowStore>>({});
|
|
32
|
+
|
|
33
|
+
const highlightFrom = Highlight_Color[props.theme].from;
|
|
34
|
+
const highlightTo = Highlight_Color[props.theme].to;
|
|
35
|
+
const highlightInter = computed(() => interpolateRgb(highlightFrom, highlightTo));
|
|
36
|
+
|
|
37
|
+
/** 存放高亮行的key*/
|
|
38
|
+
const highlightDimRowKeys = new Set<UniqKey>();
|
|
20
39
|
/** 高亮后渐暗的行定时器 */
|
|
21
40
|
const highlightDimRowsTimeout = new Map();
|
|
22
41
|
/** 高亮后渐暗的单元格定时器 */
|
|
@@ -36,9 +55,8 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
|
|
|
36
55
|
const recursion = () => {
|
|
37
56
|
window.setTimeout(() => {
|
|
38
57
|
const nowTs = Date.now();
|
|
39
|
-
const needDeleteRows: any = [];
|
|
40
58
|
|
|
41
|
-
|
|
59
|
+
highlightDimRowKeys.forEach(rowKeyValue => {
|
|
42
60
|
// const rowKeyValue = rowKeyGen(row);
|
|
43
61
|
// const rowEl = tableContainer.value?.querySelector<HTMLElement>(`[data-row-key="${rowKeyValue}"]`);
|
|
44
62
|
// if (rowEl && row._bgc_progress === 0) {
|
|
@@ -47,21 +65,18 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
|
|
|
47
65
|
// void rowEl.offsetHeight; // reflow
|
|
48
66
|
// rowEl.classList.add('highlight-row-transition');
|
|
49
67
|
// }
|
|
50
|
-
|
|
68
|
+
const highlightItem = highlightRowStore.value[rowKeyValue];
|
|
51
69
|
/** 经过的时间 ÷ 高亮持续时间 计算出 颜色过渡进度 (0-1) */
|
|
52
|
-
const progress = (nowTs -
|
|
53
|
-
// row._bgc_progress = progress;
|
|
70
|
+
const progress = (nowTs - highlightItem.bgc_progress_ms) / Highlight_Duration;
|
|
54
71
|
if (0 < progress && progress < 1) {
|
|
55
|
-
|
|
72
|
+
highlightItem.bgc = highlightInter.value(progress);
|
|
56
73
|
} else {
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
highlightItem.bgc = ''; // 清空颜色
|
|
75
|
+
highlightDimRowKeys.delete(rowKeyValue);
|
|
59
76
|
}
|
|
60
77
|
});
|
|
61
|
-
needDeleteRows.forEach((row: any) => highlightDimRows.delete(row));
|
|
62
|
-
// TODO: shallowRef 时,需要手动更新
|
|
63
78
|
|
|
64
|
-
if (
|
|
79
|
+
if (highlightDimRowKeys.size > 0) {
|
|
65
80
|
// 还有高亮的行,则下一次循环
|
|
66
81
|
recursion();
|
|
67
82
|
} else {
|
|
@@ -78,16 +93,16 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
|
|
|
78
93
|
// TODO: 支持动态计算高亮颜色。不易实现。需记录每一个单元格的颜色情况。
|
|
79
94
|
const cellEl = tableContainer.value?.querySelector<HTMLElement>(`[data-row-key="${rowKeyValue}"]>[data-index="${dataIndex}"]`);
|
|
80
95
|
if (!cellEl) return;
|
|
81
|
-
if (cellEl.classList.contains(
|
|
82
|
-
cellEl.classList.remove(
|
|
96
|
+
if (cellEl.classList.contains(HIGHLIGHT_CELL_CLASS)) {
|
|
97
|
+
cellEl.classList.remove(HIGHLIGHT_CELL_CLASS);
|
|
83
98
|
void cellEl.offsetHeight; // 通知浏览器重绘
|
|
84
99
|
}
|
|
85
|
-
cellEl.classList.add(
|
|
100
|
+
cellEl.classList.add(HIGHLIGHT_CELL_CLASS);
|
|
86
101
|
window.clearTimeout(highlightDimCellsTimeout.get(rowKeyValue));
|
|
87
102
|
highlightDimCellsTimeout.set(
|
|
88
103
|
rowKeyValue,
|
|
89
104
|
window.setTimeout(() => {
|
|
90
|
-
cellEl.classList.remove(
|
|
105
|
+
cellEl.classList.remove(HIGHLIGHT_CELL_CLASS);
|
|
91
106
|
highlightDimCellsTimeout.delete(rowKeyValue);
|
|
92
107
|
}, Highlight_Duration),
|
|
93
108
|
);
|
|
@@ -97,18 +112,19 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
|
|
|
97
112
|
* 高亮一行
|
|
98
113
|
* @param rowKeyValues
|
|
99
114
|
*/
|
|
100
|
-
function setHighlightDimRow(rowKeyValues:
|
|
115
|
+
function setHighlightDimRow(rowKeyValues: UniqKey[]) {
|
|
101
116
|
if (!Array.isArray(rowKeyValues)) rowKeyValues = [rowKeyValues];
|
|
102
117
|
if (props.virtual) {
|
|
103
118
|
// --------虚拟滚动用js计算颜色渐变的高亮方案
|
|
104
119
|
const nowTs = Date.now(); // 重置渐变进度
|
|
105
120
|
for (let i = 0; i < rowKeyValues.length; i++) {
|
|
106
121
|
const rowKeyValue = rowKeyValues[i];
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
122
|
+
highlightRowStore.value[rowKeyValue] = {
|
|
123
|
+
bgc: '',
|
|
124
|
+
bgc_progress: 0,
|
|
125
|
+
bgc_progress_ms: nowTs,
|
|
126
|
+
};
|
|
127
|
+
highlightDimRowKeys.add(rowKeyValue);
|
|
112
128
|
}
|
|
113
129
|
calcHighlightLoop();
|
|
114
130
|
} else {
|
|
@@ -121,8 +137,8 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
|
|
|
121
137
|
const rowKeyValue = rowKeyValues[i];
|
|
122
138
|
const rowEl = tableContainer.value?.querySelector<HTMLTableRowElement>(`[data-row-key="${rowKeyValue}"]`);
|
|
123
139
|
if (!rowEl) continue;
|
|
124
|
-
if (rowEl.classList.contains(
|
|
125
|
-
rowEl.classList.remove(
|
|
140
|
+
if (rowEl.classList.contains(HIGHLIGHT_ROW_CLASS)) {
|
|
141
|
+
rowEl.classList.remove(HIGHLIGHT_ROW_CLASS);
|
|
126
142
|
needRepaint = true;
|
|
127
143
|
}
|
|
128
144
|
rowElTemp.push(rowEl);
|
|
@@ -131,7 +147,7 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
|
|
|
131
147
|
highlightDimRowsTimeout.set(
|
|
132
148
|
rowKeyValue,
|
|
133
149
|
window.setTimeout(() => {
|
|
134
|
-
rowEl.classList.remove(
|
|
150
|
+
rowEl.classList.remove(HIGHLIGHT_ROW_CLASS);
|
|
135
151
|
highlightDimRowsTimeout.delete(rowKeyValue); // 回收内存
|
|
136
152
|
}, Highlight_Duration),
|
|
137
153
|
);
|
|
@@ -139,11 +155,12 @@ export function useHighlight({ props, tableContainer, rowKeyGen }: Params) {
|
|
|
139
155
|
if (needRepaint) {
|
|
140
156
|
void tableContainer.value?.offsetWidth; //强制浏览器重绘
|
|
141
157
|
}
|
|
142
|
-
rowElTemp.forEach(el => el.classList.add(
|
|
158
|
+
rowElTemp.forEach(el => el.classList.add(HIGHLIGHT_ROW_CLASS)); // 统一添加动画
|
|
143
159
|
}
|
|
144
160
|
}
|
|
145
161
|
|
|
146
162
|
return {
|
|
163
|
+
highlightRowStore,
|
|
147
164
|
setHighlightDimRow,
|
|
148
165
|
setHighlightDimCell,
|
|
149
166
|
};
|
package/src/StkTable/utils.ts
CHANGED
|
@@ -67,12 +67,12 @@ function strCompare(a: string, b: string, type: 'number' | 'string'): number {
|
|
|
67
67
|
* 分离出空数据和非空数据成两个数组
|
|
68
68
|
* @param sortOption
|
|
69
69
|
* @param targetDataSource
|
|
70
|
-
* @param isNumber 1
|
|
70
|
+
* @param isNumber 1 数字
|
|
71
71
|
* @return [值数组,空数组]
|
|
72
72
|
*/
|
|
73
|
-
function separatedData(sortOption: SortOption
|
|
74
|
-
const emptyArr:
|
|
75
|
-
const valueArr:
|
|
73
|
+
function separatedData<T extends Record<string, any>>(sortOption: SortOption<T>, targetDataSource: T[], isNumber?: boolean) {
|
|
74
|
+
const emptyArr: T[] = [];
|
|
75
|
+
const valueArr: T[] = [];
|
|
76
76
|
|
|
77
77
|
for (let i = 0; i < targetDataSource.length; i++) {
|
|
78
78
|
const row = targetDataSource[i];
|
|
@@ -96,20 +96,33 @@ function separatedData(sortOption: SortOption, targetDataSource: any[], isNumber
|
|
|
96
96
|
* 可以在组件外部自己实现表格排序,组件配置remote,使表格不排序。
|
|
97
97
|
* 使用者在@sort-change事件中自行更改table props 'dataSource'完成排序。
|
|
98
98
|
* TODO: key 唯一值,排序字段相同时,根据唯一值排序。
|
|
99
|
+
*
|
|
100
|
+
* sortConfig.defaultSort 会在order为null时生效
|
|
99
101
|
* @param sortOption 列配置
|
|
100
102
|
* @param order 排序方式
|
|
101
103
|
* @param dataSource 排序的数组
|
|
102
104
|
*/
|
|
103
|
-
export function tableSort
|
|
105
|
+
export function tableSort<T extends Record<string, any>>(
|
|
106
|
+
sortOption: SortOption<T>,
|
|
107
|
+
order: Order,
|
|
108
|
+
dataSource: T[],
|
|
109
|
+
sortConfig: SortConfig<T> = {},
|
|
110
|
+
): T[] {
|
|
104
111
|
if (!dataSource?.length) return dataSource || [];
|
|
105
|
-
sortConfig =
|
|
112
|
+
sortConfig = { emptyToBottom: false, ...sortConfig };
|
|
106
113
|
let targetDataSource = [...dataSource];
|
|
114
|
+
let sortField = sortOption.sortField || sortOption.dataIndex;
|
|
115
|
+
|
|
116
|
+
if (!order && sortConfig.defaultSort) {
|
|
117
|
+
// 默认排序
|
|
118
|
+
order = sortConfig.defaultSort.order;
|
|
119
|
+
sortField = sortConfig.defaultSort.dataIndex;
|
|
120
|
+
}
|
|
107
121
|
|
|
108
122
|
if (typeof sortOption.sorter === 'function') {
|
|
109
123
|
const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });
|
|
110
124
|
if (customSorterData) targetDataSource = customSorterData;
|
|
111
125
|
} else if (order) {
|
|
112
|
-
const sortField = sortOption.sortField || sortOption.dataIndex;
|
|
113
126
|
let { sortType } = sortOption;
|
|
114
127
|
if (!sortType) sortType = typeof dataSource[0][sortField] as 'number' | 'string';
|
|
115
128
|
|