stk-table-vue 0.8.7 → 0.8.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 +2 -1
- package/lib/src/StkTable/StkTable.vue.d.ts +19 -11
- package/lib/src/StkTable/const.d.ts +9 -1
- package/lib/src/StkTable/types/index.d.ts +28 -14
- package/lib/src/StkTable/useMergeCells.d.ts +8 -8
- package/lib/stk-table-vue.js +99 -54
- package/package.json +5 -5
- package/src/StkTable/StkTable.vue +67 -30
- package/src/StkTable/const.ts +14 -1
- package/src/StkTable/types/index.ts +29 -14
- package/src/StkTable/useKeyboardArrowScroll.ts +10 -10
- package/src/StkTable/useMergeCells.ts +12 -19
- package/src/StkTable/utils/index.ts +24 -11
package/README.md
CHANGED
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
## Documentation
|
|
23
|
-
### [Stk Table Vue Official
|
|
23
|
+
### [Stk Table Vue Official en](https://ja-plus.github.io/stk-table-vue/en/)
|
|
24
|
+
### [Stk Table Vue Official zh-CN](https://ja-plus.github.io/stk-table-vue/)
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
## Repo:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AutoRowHeightConfig, ColResizableConfig, DragRowConfig, ExpandConfig, HeaderDragConfig, HighlightConfig, Order, PrivateRowDT, PrivateStkTableColumn, SeqConfig, SortConfig, SortOption, StkTableColumn, TreeConfig, UniqKey, UniqKeyProp } from './types/index';
|
|
1
|
+
import { AutoRowHeightConfig, ColResizableConfig, DragRowConfig, ExpandConfig, HeaderDragConfig, HighlightConfig, Order, PrivateRowDT, PrivateStkTableColumn, RowActiveOption, SeqConfig, SortConfig, SortOption, StkTableColumn, TreeConfig, UniqKey, UniqKeyProp } from './types/index';
|
|
2
2
|
|
|
3
3
|
/** Generic stands for DataType */
|
|
4
4
|
type DT = any & PrivateRowDT;
|
|
@@ -6,9 +6,11 @@ type DT = any & PrivateRowDT;
|
|
|
6
6
|
* 选中一行
|
|
7
7
|
* @param {string} rowKeyOrRow selected rowKey, undefined to unselect
|
|
8
8
|
* @param {boolean} option.silent if set true not emit `current-change`. default:false
|
|
9
|
+
* @param {boolean} option.deep if set true, deep search in children. default:false
|
|
9
10
|
*/
|
|
10
11
|
declare function setCurrentRow(rowKeyOrRow: string | undefined | DT, option?: {
|
|
11
|
-
silent
|
|
12
|
+
silent?: boolean;
|
|
13
|
+
deep?: boolean;
|
|
12
14
|
}): void;
|
|
13
15
|
/**
|
|
14
16
|
* set highlight active cell (props.cellActive=true)
|
|
@@ -90,8 +92,10 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
90
92
|
/** 是否高亮鼠标悬浮的行 */
|
|
91
93
|
rowHover?: boolean;
|
|
92
94
|
/** 是否高亮选中的行 */
|
|
93
|
-
rowActive?: boolean
|
|
94
|
-
/**
|
|
95
|
+
rowActive?: boolean | RowActiveOption<DT>;
|
|
96
|
+
/**
|
|
97
|
+
* @deprecated
|
|
98
|
+
*/
|
|
95
99
|
rowCurrentRevokable?: boolean;
|
|
96
100
|
/** 表头行高。default = rowHeight */
|
|
97
101
|
headerRowHeight?: number | string | null;
|
|
@@ -238,8 +242,9 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
238
242
|
fixedColShadow: boolean;
|
|
239
243
|
optimizeVue2Scroll: boolean;
|
|
240
244
|
sortConfig: () => {
|
|
241
|
-
emptyToBottom:
|
|
242
|
-
stringLocaleCompare:
|
|
245
|
+
emptyToBottom: false;
|
|
246
|
+
stringLocaleCompare: false;
|
|
247
|
+
sortChildren: false;
|
|
243
248
|
};
|
|
244
249
|
hideHeaderTitle: boolean;
|
|
245
250
|
highlightConfig: () => {};
|
|
@@ -456,8 +461,10 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
456
461
|
/** 是否高亮鼠标悬浮的行 */
|
|
457
462
|
rowHover?: boolean;
|
|
458
463
|
/** 是否高亮选中的行 */
|
|
459
|
-
rowActive?: boolean
|
|
460
|
-
/**
|
|
464
|
+
rowActive?: boolean | RowActiveOption<DT>;
|
|
465
|
+
/**
|
|
466
|
+
* @deprecated
|
|
467
|
+
*/
|
|
461
468
|
rowCurrentRevokable?: boolean;
|
|
462
469
|
/** 表头行高。default = rowHeight */
|
|
463
470
|
headerRowHeight?: number | string | null;
|
|
@@ -604,8 +611,9 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
604
611
|
fixedColShadow: boolean;
|
|
605
612
|
optimizeVue2Scroll: boolean;
|
|
606
613
|
sortConfig: () => {
|
|
607
|
-
emptyToBottom:
|
|
608
|
-
stringLocaleCompare:
|
|
614
|
+
emptyToBottom: false;
|
|
615
|
+
stringLocaleCompare: false;
|
|
616
|
+
sortChildren: false;
|
|
609
617
|
};
|
|
610
618
|
hideHeaderTitle: boolean;
|
|
611
619
|
highlightConfig: () => {};
|
|
@@ -683,7 +691,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
683
691
|
fixedMode: boolean;
|
|
684
692
|
theme: "light" | "dark";
|
|
685
693
|
rowHover: boolean;
|
|
686
|
-
rowActive: boolean
|
|
694
|
+
rowActive: boolean | RowActiveOption<DT>;
|
|
687
695
|
rowCurrentRevokable: boolean;
|
|
688
696
|
virtual: boolean;
|
|
689
697
|
virtualX: boolean;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { RowActiveOption } from './types';
|
|
2
|
+
|
|
1
3
|
export declare const DEFAULT_COL_WIDTH = "100";
|
|
2
4
|
export declare const DEFAULT_TABLE_HEIGHT = 100;
|
|
3
5
|
export declare const DEFAULT_TABLE_WIDTH = 200;
|
|
@@ -24,5 +26,11 @@ export declare const DEFAULT_SMOOTH_SCROLL: boolean;
|
|
|
24
26
|
export declare const STK_ID_PREFIX = "stk";
|
|
25
27
|
/** expanded row key prefix */
|
|
26
28
|
export declare const EXPANDED_ROW_KEY_PREFIX = "expanded-";
|
|
27
|
-
/** cell key
|
|
29
|
+
/** cell key split str */
|
|
28
30
|
export declare const CELL_KEY_SEPARATE = "--";
|
|
31
|
+
export declare const DEFAULT_SORT_CONFIG: {
|
|
32
|
+
emptyToBottom: false;
|
|
33
|
+
stringLocaleCompare: false;
|
|
34
|
+
sortChildren: false;
|
|
35
|
+
};
|
|
36
|
+
export declare const DEFAULT_ROW_ACTIVE_CONFIG: Required<RowActiveOption<any>>;
|
|
@@ -84,7 +84,7 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
84
84
|
/** 排序方式。按数字/字符串 */
|
|
85
85
|
sortType?: 'number' | 'string';
|
|
86
86
|
/** 配置当前列的排序规则 */
|
|
87
|
-
sortConfig?:
|
|
87
|
+
sortConfig?: Omit<SortConfig<T>, 'defaultSort'>;
|
|
88
88
|
/** 固定列 */
|
|
89
89
|
fixed?: 'left' | 'right' | null;
|
|
90
90
|
/**
|
|
@@ -167,17 +167,17 @@ export type UniqKey = string | number;
|
|
|
167
167
|
export type UniqKeyFun = (param: any) => UniqKey;
|
|
168
168
|
export type UniqKeyProp = UniqKey | UniqKeyFun;
|
|
169
169
|
export type SortConfig<T extends Record<string, any>> = {
|
|
170
|
-
/** 空值始终排在列表末尾 */
|
|
171
|
-
emptyToBottom?: boolean;
|
|
172
170
|
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
171
|
+
* 1. trigger when init
|
|
172
|
+
* 2. trigger when sort direction is null
|
|
175
173
|
*/
|
|
176
174
|
defaultSort?: {
|
|
177
175
|
/**
|
|
178
|
-
*
|
|
176
|
+
* colKey
|
|
177
|
+
*
|
|
178
|
+
* if set `props.colKey`
|
|
179
179
|
*
|
|
180
|
-
*
|
|
180
|
+
* default: StkTableColumn<T>['dataIndex']
|
|
181
181
|
*/
|
|
182
182
|
key?: StkTableColumn<T>['key'];
|
|
183
183
|
dataIndex: StkTableColumn<T>['dataIndex'];
|
|
@@ -185,14 +185,22 @@ export type SortConfig<T extends Record<string, any>> = {
|
|
|
185
185
|
sortField?: StkTableColumn<T>['sortField'];
|
|
186
186
|
sortType?: StkTableColumn<T>['sortType'];
|
|
187
187
|
sorter?: StkTableColumn<T>['sorter'];
|
|
188
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* whether to disable trigger`sort-change` event. default: false
|
|
190
|
+
*/
|
|
189
191
|
silent?: boolean;
|
|
190
192
|
};
|
|
193
|
+
/** empty value always sort to bottom */
|
|
194
|
+
emptyToBottom?: boolean;
|
|
191
195
|
/**
|
|
192
196
|
* string sort if use `String.prototype.localCompare`
|
|
193
197
|
* default: false
|
|
194
198
|
*/
|
|
195
199
|
stringLocaleCompare?: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* whether to sort children when sort current column. default: false
|
|
202
|
+
*/
|
|
203
|
+
sortChildren?: boolean;
|
|
196
204
|
};
|
|
197
205
|
/** th td type */
|
|
198
206
|
export declare const enum TagType {
|
|
@@ -225,7 +233,6 @@ export type ExpandedRow = PrivateRowDT & {
|
|
|
225
233
|
export type DragRowConfig = {
|
|
226
234
|
mode?: 'none' | 'insert' | 'swap';
|
|
227
235
|
};
|
|
228
|
-
/** 树形配置 */
|
|
229
236
|
export type TreeConfig = {
|
|
230
237
|
defaultExpandAll?: boolean;
|
|
231
238
|
defaultExpandKeys?: UniqKey[];
|
|
@@ -234,13 +241,13 @@ export type TreeConfig = {
|
|
|
234
241
|
/** header drag config */
|
|
235
242
|
export type HeaderDragConfig<DT extends Record<string, any> = any> = {
|
|
236
243
|
/**
|
|
237
|
-
*
|
|
238
|
-
* - none
|
|
239
|
-
* - insert -
|
|
240
|
-
* - swap
|
|
244
|
+
* col switch mode
|
|
245
|
+
* - none
|
|
246
|
+
* - insert - (default)
|
|
247
|
+
* - swap
|
|
241
248
|
*/
|
|
242
249
|
mode?: 'none' | 'insert' | 'swap';
|
|
243
|
-
/**
|
|
250
|
+
/** disabled drag col */
|
|
244
251
|
disabled?: (col: StkTableColumn<DT>) => boolean;
|
|
245
252
|
};
|
|
246
253
|
export type AutoRowHeightConfig<DT> = {
|
|
@@ -253,4 +260,11 @@ export type ColResizableConfig<DT extends Record<string, any>> = {
|
|
|
253
260
|
export type RowKeyGen = (row: any) => UniqKey;
|
|
254
261
|
export type ColKeyGen = ComputedRef<(col: StkTableColumn<any>) => UniqKey>;
|
|
255
262
|
export type CellKeyGen = (row: any, col: StkTableColumn<any>) => string;
|
|
263
|
+
export type RowActiveOption<DT> = {
|
|
264
|
+
enabled?: boolean;
|
|
265
|
+
/** disabled row active */
|
|
266
|
+
disabled?: (row: DT) => boolean;
|
|
267
|
+
/** current row again click can revoke active */
|
|
268
|
+
revokable?: boolean;
|
|
269
|
+
};
|
|
256
270
|
export {};
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { ShallowRef } from 'vue';
|
|
2
|
-
import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
|
|
1
|
+
import { Ref, ShallowRef } from 'vue';
|
|
2
|
+
import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowActiveOption, RowKeyGen, UniqKey } from './types';
|
|
3
3
|
|
|
4
4
|
type Options = {
|
|
5
|
-
|
|
5
|
+
rowActiveProp: Ref<RowActiveOption<any>>;
|
|
6
6
|
tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
|
|
7
7
|
rowKeyGen: RowKeyGen;
|
|
8
8
|
colKeyGen: ColKeyGen;
|
|
9
9
|
virtual_dataSourcePart: ShallowRef<any[]>;
|
|
10
10
|
};
|
|
11
|
-
export declare function useMergeCells({
|
|
12
|
-
hiddenCellMap:
|
|
11
|
+
export declare function useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart }: Options): {
|
|
12
|
+
hiddenCellMap: Ref<Record<UniqKey, Set<UniqKey>>, Record<UniqKey, Set<UniqKey>>>;
|
|
13
13
|
mergeCellsWrapper: (row: MergeCellsParam<any>["row"], col: MergeCellsParam<any>["col"], rowIndex: MergeCellsParam<any>["rowIndex"], colIndex: MergeCellsParam<any>["colIndex"]) => {
|
|
14
14
|
colspan?: number;
|
|
15
15
|
rowspan?: number;
|
|
16
16
|
} | undefined;
|
|
17
|
-
hoverMergedCells:
|
|
17
|
+
hoverMergedCells: Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
|
|
18
18
|
updateHoverMergedCells: (rowKey: UniqKey | undefined) => void;
|
|
19
|
-
activeMergedCells:
|
|
20
|
-
updateActiveMergedCells: (clear?: boolean) => void;
|
|
19
|
+
activeMergedCells: Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
|
|
20
|
+
updateActiveMergedCells: (clear?: boolean, rowKey?: UniqKey) => void;
|
|
21
21
|
};
|
|
22
22
|
export {};
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -134,30 +134,41 @@ function separatedData(sortOption, targetDataSource, isNumber) {
|
|
|
134
134
|
}
|
|
135
135
|
function tableSort(sortOption, order, dataSource, sortConfig = {}) {
|
|
136
136
|
if (!(dataSource == null ? void 0 : dataSource.length) || !sortOption) return dataSource || [];
|
|
137
|
-
sortConfig = {
|
|
137
|
+
sortConfig = { ...DEFAULT_SORT_CONFIG, ...sortConfig };
|
|
138
138
|
let targetDataSource = dataSource.slice();
|
|
139
139
|
let sortField = sortOption.sortField || sortOption.dataIndex;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
const { defaultSort, stringLocaleCompare, emptyToBottom, sortChildren } = sortConfig;
|
|
141
|
+
if (!order && defaultSort) {
|
|
142
|
+
order = defaultSort.order;
|
|
143
|
+
sortField = defaultSort.dataIndex;
|
|
143
144
|
}
|
|
144
145
|
if (typeof sortOption.sorter === "function") {
|
|
145
146
|
const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });
|
|
146
147
|
if (customSorterData) targetDataSource = customSorterData;
|
|
148
|
+
if (sortChildren) {
|
|
149
|
+
targetDataSource.forEach((item) => {
|
|
150
|
+
var _a;
|
|
151
|
+
if (!((_a = item.children) == null ? void 0 : _a.length)) return;
|
|
152
|
+
item.children = tableSort(sortOption, order, item.children, sortConfig);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
147
155
|
} else if (order) {
|
|
148
156
|
let { sortType } = sortOption;
|
|
149
157
|
if (!sortType) sortType = typeof dataSource[0][sortField];
|
|
150
158
|
const isNumber = sortType === "number";
|
|
151
159
|
const [valueArr, emptyArr] = separatedData(sortOption, targetDataSource, isNumber);
|
|
152
160
|
if (order === "asc") {
|
|
153
|
-
valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber,
|
|
154
|
-
} else {
|
|
155
|
-
valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, sortConfig.stringLocaleCompare));
|
|
156
|
-
}
|
|
157
|
-
if (order === "desc" || sortConfig.emptyToBottom) {
|
|
158
|
-
targetDataSource = valueArr.concat(emptyArr);
|
|
161
|
+
valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, stringLocaleCompare));
|
|
159
162
|
} else {
|
|
160
|
-
|
|
163
|
+
valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, stringLocaleCompare));
|
|
164
|
+
}
|
|
165
|
+
targetDataSource = order === "desc" || emptyToBottom ? valueArr.concat(emptyArr) : emptyArr.concat(valueArr);
|
|
166
|
+
if (sortChildren) {
|
|
167
|
+
targetDataSource.forEach((item) => {
|
|
168
|
+
var _a;
|
|
169
|
+
if (!((_a = item.children) == null ? void 0 : _a.length)) return;
|
|
170
|
+
item.children = tableSort(sortOption, order, item.children, sortConfig);
|
|
171
|
+
});
|
|
161
172
|
}
|
|
162
173
|
}
|
|
163
174
|
return targetDataSource;
|
|
@@ -210,6 +221,16 @@ const DEFAULT_SMOOTH_SCROLL = _chromeVersion < 85;
|
|
|
210
221
|
const STK_ID_PREFIX = "stk";
|
|
211
222
|
const EXPANDED_ROW_KEY_PREFIX = "expanded-";
|
|
212
223
|
const CELL_KEY_SEPARATE = "--";
|
|
224
|
+
const DEFAULT_SORT_CONFIG = {
|
|
225
|
+
emptyToBottom: false,
|
|
226
|
+
stringLocaleCompare: false,
|
|
227
|
+
sortChildren: false
|
|
228
|
+
};
|
|
229
|
+
const DEFAULT_ROW_ACTIVE_CONFIG = {
|
|
230
|
+
enabled: false,
|
|
231
|
+
disabled: () => false,
|
|
232
|
+
revokable: false
|
|
233
|
+
};
|
|
213
234
|
var TagType = /* @__PURE__ */ ((TagType2) => {
|
|
214
235
|
TagType2[TagType2["TH"] = 0] = "TH";
|
|
215
236
|
TagType2[TagType2["TD"] = 1] = "TD";
|
|
@@ -817,7 +838,8 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
817
838
|
}
|
|
818
839
|
function handleKeydown(e) {
|
|
819
840
|
if (!virtual_on.value) return;
|
|
820
|
-
|
|
841
|
+
const keyCode = e.code;
|
|
842
|
+
if (!ScrollCodesValues.includes(keyCode)) return;
|
|
821
843
|
if (!isMouseOver) return;
|
|
822
844
|
e.preventDefault();
|
|
823
845
|
const { scrollTop, rowHeight, containerHeight, scrollHeight } = virtualScroll.value;
|
|
@@ -825,21 +847,21 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
825
847
|
const { headless, headerRowHeight } = props;
|
|
826
848
|
const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
|
|
827
849
|
const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
|
|
828
|
-
if (
|
|
850
|
+
if (keyCode === "ArrowUp") {
|
|
829
851
|
scrollTo(scrollTop - rowHeight, null);
|
|
830
|
-
} else if (
|
|
852
|
+
} else if (keyCode === "ArrowRight") {
|
|
831
853
|
scrollTo(null, scrollLeft + 50);
|
|
832
|
-
} else if (
|
|
854
|
+
} else if (keyCode === "ArrowDown") {
|
|
833
855
|
scrollTo(scrollTop + rowHeight, null);
|
|
834
|
-
} else if (
|
|
856
|
+
} else if (keyCode === "ArrowLeft") {
|
|
835
857
|
scrollTo(null, scrollLeft - 50);
|
|
836
|
-
} else if (
|
|
858
|
+
} else if (keyCode === "PageUp") {
|
|
837
859
|
scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
|
|
838
|
-
} else if (
|
|
860
|
+
} else if (keyCode === "PageDown") {
|
|
839
861
|
scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
|
|
840
|
-
} else if (
|
|
862
|
+
} else if (keyCode === "Home") {
|
|
841
863
|
scrollTo(0, null);
|
|
842
|
-
} else if (
|
|
864
|
+
} else if (keyCode === "End") {
|
|
843
865
|
scrollTo(scrollHeight, null);
|
|
844
866
|
}
|
|
845
867
|
}
|
|
@@ -886,13 +908,7 @@ function useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy }) {
|
|
|
886
908
|
updateMaxRowSpan
|
|
887
909
|
};
|
|
888
910
|
}
|
|
889
|
-
function useMergeCells({
|
|
890
|
-
props,
|
|
891
|
-
tableHeaderLast,
|
|
892
|
-
rowKeyGen,
|
|
893
|
-
colKeyGen,
|
|
894
|
-
virtual_dataSourcePart
|
|
895
|
-
}) {
|
|
911
|
+
function useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart }) {
|
|
896
912
|
const hiddenCellMap = ref({});
|
|
897
913
|
const hoverRowMap = ref({});
|
|
898
914
|
const hoverMergedCells = ref(/* @__PURE__ */ new Set());
|
|
@@ -937,13 +953,13 @@ function useMergeCells({
|
|
|
937
953
|
const set = rowKey === void 0 ? null : hoverRowMap.value[rowKey];
|
|
938
954
|
hoverMergedCells.value = set || /* @__PURE__ */ new Set();
|
|
939
955
|
}
|
|
940
|
-
function updateActiveMergedCells(clear) {
|
|
941
|
-
if (!
|
|
956
|
+
function updateActiveMergedCells(clear, rowKey) {
|
|
957
|
+
if (!rowActiveProp.value.enabled) return;
|
|
942
958
|
if (clear) {
|
|
943
959
|
activeMergedCells.value.clear();
|
|
944
|
-
|
|
945
|
-
activeMergedCells.value = new Set(hoverMergedCells.value);
|
|
960
|
+
return;
|
|
946
961
|
}
|
|
962
|
+
activeMergedCells.value = rowKey !== void 0 && hoverRowMap.value[rowKey] || new Set(hoverMergedCells.value);
|
|
947
963
|
}
|
|
948
964
|
return {
|
|
949
965
|
hiddenCellMap,
|
|
@@ -1751,10 +1767,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1751
1767
|
autoResize: { type: [Boolean, Function], default: true },
|
|
1752
1768
|
fixedColShadow: { type: Boolean, default: false },
|
|
1753
1769
|
optimizeVue2Scroll: { type: Boolean, default: false },
|
|
1754
|
-
sortConfig: { default: () =>
|
|
1755
|
-
emptyToBottom: false,
|
|
1756
|
-
stringLocaleCompare: false
|
|
1757
|
-
}) },
|
|
1770
|
+
sortConfig: { default: () => DEFAULT_SORT_CONFIG },
|
|
1758
1771
|
hideHeaderTitle: { type: [Boolean, Array], default: false },
|
|
1759
1772
|
highlightConfig: { default: () => ({}) },
|
|
1760
1773
|
seqConfig: { default: () => ({}) },
|
|
@@ -1788,6 +1801,18 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1788
1801
|
const isTreeData = computed(() => {
|
|
1789
1802
|
return props.columns.some((col) => col.type === "tree-node");
|
|
1790
1803
|
});
|
|
1804
|
+
const rowActiveProp = computed(() => {
|
|
1805
|
+
const { rowActive } = props;
|
|
1806
|
+
if (typeof rowActive === "boolean") {
|
|
1807
|
+
return {
|
|
1808
|
+
...DEFAULT_ROW_ACTIVE_CONFIG,
|
|
1809
|
+
enabled: rowActive,
|
|
1810
|
+
revokable: Boolean(props.rowCurrentRevokable)
|
|
1811
|
+
};
|
|
1812
|
+
} else {
|
|
1813
|
+
return { ...DEFAULT_ROW_ACTIVE_CONFIG, ...rowActive };
|
|
1814
|
+
}
|
|
1815
|
+
});
|
|
1791
1816
|
const dataSourceCopy = shallowRef([]);
|
|
1792
1817
|
const rowKeyGenComputed = computed(() => {
|
|
1793
1818
|
const { rowKey } = props;
|
|
@@ -1821,7 +1846,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1821
1846
|
});
|
|
1822
1847
|
const SRBRBottomHeight = computed(() => {
|
|
1823
1848
|
if (!isSRBRActive.value || !props.virtual) return 0;
|
|
1824
|
-
|
|
1849
|
+
const { containerHeight, rowHeight } = virtualScroll.value;
|
|
1850
|
+
return (containerHeight - tableHeaderHeight.value) % rowHeight;
|
|
1825
1851
|
});
|
|
1826
1852
|
const rowKeyGenCache = /* @__PURE__ */ new WeakMap();
|
|
1827
1853
|
const { isSRBRActive } = useScrollRowByRow({ props, tableContainerRef });
|
|
@@ -1854,7 +1880,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1854
1880
|
updateHoverMergedCells,
|
|
1855
1881
|
activeMergedCells,
|
|
1856
1882
|
updateActiveMergedCells
|
|
1857
|
-
} = useMergeCells({
|
|
1883
|
+
} = useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
|
|
1858
1884
|
const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeadersForCalc });
|
|
1859
1885
|
const getFixedStyle = useFixedStyle({
|
|
1860
1886
|
props,
|
|
@@ -2118,8 +2144,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
2118
2144
|
if (click) sortOrderIndex.value++;
|
|
2119
2145
|
sortOrderIndex.value = sortOrderIndex.value % 3;
|
|
2120
2146
|
let order = sortSwitchOrder[sortOrderIndex.value];
|
|
2121
|
-
const sortConfig = { ...props.sortConfig, ...col.sortConfig };
|
|
2122
|
-
const defaultSort = sortConfig
|
|
2147
|
+
const sortConfig = { ...DEFAULT_SORT_CONFIG, ...props.sortConfig, ...col.sortConfig };
|
|
2148
|
+
const { defaultSort } = sortConfig;
|
|
2123
2149
|
const colKeyGenValue = colKeyGen.value;
|
|
2124
2150
|
if (!order && defaultSort) {
|
|
2125
2151
|
const defaultColKey = defaultSort.key || defaultSort.dataIndex;
|
|
@@ -2143,30 +2169,30 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
2143
2169
|
}
|
|
2144
2170
|
}
|
|
2145
2171
|
}
|
|
2172
|
+
let dataSourceTemp = props.dataSource.slice();
|
|
2146
2173
|
if (!props.sortRemote || options.force) {
|
|
2147
2174
|
const sortOption = col || defaultSort;
|
|
2148
2175
|
if (sortOption) {
|
|
2149
|
-
|
|
2176
|
+
dataSourceTemp = tableSort(sortOption, order, dataSourceTemp, sortConfig);
|
|
2177
|
+
dataSourceCopy.value = isTreeData.value ? flatTreeData(dataSourceTemp) : dataSourceTemp;
|
|
2150
2178
|
}
|
|
2151
2179
|
}
|
|
2152
2180
|
if (click || options.emit) {
|
|
2153
|
-
emits("sort-change", col, order, toRaw(
|
|
2181
|
+
emits("sort-change", col, order, toRaw(dataSourceTemp), sortConfig);
|
|
2154
2182
|
}
|
|
2155
2183
|
}
|
|
2156
2184
|
function onRowClick(e, row, rowIndex) {
|
|
2185
|
+
var _a, _b;
|
|
2157
2186
|
emits("row-click", e, row, { rowIndex });
|
|
2187
|
+
if ((_b = (_a = rowActiveProp.value).disabled) == null ? void 0 : _b.call(_a, row)) return;
|
|
2158
2188
|
const isCurrentRow = props.rowKey ? currentRowKey.value === rowKeyGen(row) : currentRow.value === row;
|
|
2159
2189
|
if (isCurrentRow) {
|
|
2160
|
-
if (!
|
|
2190
|
+
if (!rowActiveProp.value.revokable) {
|
|
2161
2191
|
return;
|
|
2162
2192
|
}
|
|
2163
|
-
|
|
2164
|
-
currentRowKey.value = void 0;
|
|
2165
|
-
updateActiveMergedCells(true);
|
|
2193
|
+
setCurrentRow(void 0, { silent: true });
|
|
2166
2194
|
} else {
|
|
2167
|
-
|
|
2168
|
-
currentRowKey.value = rowKeyGen(row);
|
|
2169
|
-
updateActiveMergedCells();
|
|
2195
|
+
setCurrentRow(row, { silent: true });
|
|
2170
2196
|
}
|
|
2171
2197
|
emits("current-change", e, row, { select: !isCurrentRow });
|
|
2172
2198
|
}
|
|
@@ -2290,30 +2316,49 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
2290
2316
|
updateHoverMergedCells(void 0);
|
|
2291
2317
|
}
|
|
2292
2318
|
}
|
|
2293
|
-
function setCurrentRow(rowKeyOrRow, option = { silent: false }) {
|
|
2294
|
-
if (!dataSourceCopy.value.length) return;
|
|
2319
|
+
function setCurrentRow(rowKeyOrRow, option = { silent: false, deep: false }) {
|
|
2295
2320
|
const select = rowKeyOrRow !== void 0;
|
|
2321
|
+
const currentRowTemp = currentRow.value;
|
|
2296
2322
|
if (!select) {
|
|
2297
2323
|
currentRow.value = void 0;
|
|
2298
2324
|
currentRowKey.value = void 0;
|
|
2325
|
+
updateActiveMergedCells(true);
|
|
2299
2326
|
} else if (typeof rowKeyOrRow === "string") {
|
|
2300
|
-
const
|
|
2327
|
+
const findRowByKey = (data, key) => {
|
|
2328
|
+
var _a;
|
|
2329
|
+
for (let i = 0; i < data.length; i++) {
|
|
2330
|
+
const item = data[i];
|
|
2331
|
+
if (rowKeyGen(item) === key) {
|
|
2332
|
+
return item;
|
|
2333
|
+
}
|
|
2334
|
+
if (option.deep && ((_a = item.children) == null ? void 0 : _a.length)) {
|
|
2335
|
+
const found = findRowByKey(item.children, key);
|
|
2336
|
+
if (found) {
|
|
2337
|
+
return found;
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
return null;
|
|
2342
|
+
};
|
|
2343
|
+
currentRowKey.value = rowKeyOrRow;
|
|
2344
|
+
updateActiveMergedCells(false, currentRowKey.value);
|
|
2345
|
+
const row = findRowByKey(dataSourceCopy.value || [], rowKeyOrRow);
|
|
2301
2346
|
if (!row) {
|
|
2302
2347
|
console.warn("setCurrentRow failed.rowKey:", rowKeyOrRow);
|
|
2303
2348
|
return;
|
|
2304
2349
|
}
|
|
2305
2350
|
currentRow.value = row;
|
|
2306
|
-
currentRowKey.value = rowKeyOrRow;
|
|
2307
2351
|
} else {
|
|
2308
2352
|
currentRow.value = rowKeyOrRow;
|
|
2309
2353
|
currentRowKey.value = rowKeyGen(rowKeyOrRow);
|
|
2354
|
+
updateActiveMergedCells(false, currentRowKey.value);
|
|
2310
2355
|
}
|
|
2311
2356
|
if (!option.silent) {
|
|
2312
2357
|
emits(
|
|
2313
2358
|
"current-change",
|
|
2314
2359
|
/** no Event */
|
|
2315
2360
|
null,
|
|
2316
|
-
currentRow.value,
|
|
2361
|
+
select ? currentRow.value : currentRowTemp,
|
|
2317
2362
|
{ select }
|
|
2318
2363
|
);
|
|
2319
2364
|
}
|
|
@@ -2503,7 +2548,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
2503
2548
|
"cell-hover": props.cellHover,
|
|
2504
2549
|
"cell-active": props.cellActive,
|
|
2505
2550
|
"row-hover": props.rowHover,
|
|
2506
|
-
"row-active":
|
|
2551
|
+
"row-active": rowActiveProp.value.enabled,
|
|
2507
2552
|
"text-overflow": props.showOverflow,
|
|
2508
2553
|
"header-text-overflow": props.showHeaderOverflow,
|
|
2509
2554
|
"fixed-relative-mode": isRelativeMode.value,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stk-table-vue",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.9",
|
|
4
4
|
"description": "Simple realtime virtual table for vue3 and vue2.7",
|
|
5
5
|
"main": "./lib/stk-table-vue.js",
|
|
6
6
|
"types": "./lib/src/StkTable/index.d.ts",
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
"postcss-discard-comments": "^6.0.2",
|
|
60
60
|
"postcss-preset-env": "^9.5.11",
|
|
61
61
|
"prettier": "^3.2.5",
|
|
62
|
-
"stk-table-vue": "^0.8.
|
|
62
|
+
"stk-table-vue": "^0.8.7",
|
|
63
63
|
"typescript": "^5.8.3",
|
|
64
|
-
"vite": "^7.
|
|
64
|
+
"vite": "^7.1.7",
|
|
65
65
|
"vite-plugin-dts": "3.9.1",
|
|
66
66
|
"vitepress": "^1.6.4",
|
|
67
|
-
"vitepress-demo-plugin": "^1.4.
|
|
67
|
+
"vitepress-demo-plugin": "^1.4.7",
|
|
68
68
|
"vitepress-plugin-llms": "^1.7.5",
|
|
69
69
|
"vitest": "^3.2.4",
|
|
70
|
-
"vue": "^3.5.
|
|
70
|
+
"vue": "^3.5.22",
|
|
71
71
|
"vue-eslint-parser": "^9.4.2"
|
|
72
72
|
}
|
|
73
73
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
'cell-hover': props.cellHover,
|
|
21
21
|
'cell-active': props.cellActive,
|
|
22
22
|
'row-hover': props.rowHover,
|
|
23
|
-
'row-active':
|
|
23
|
+
'row-active': rowActiveProp.enabled,
|
|
24
24
|
'text-overflow': props.showOverflow,
|
|
25
25
|
'header-text-overflow': props.showHeaderOverflow,
|
|
26
26
|
'fixed-relative-mode': isRelativeMode,
|
|
@@ -253,7 +253,14 @@ import { CSSProperties, computed, nextTick, onMounted, ref, shallowRef, toRaw, w
|
|
|
253
253
|
import DragHandle from './components/DragHandle.vue';
|
|
254
254
|
import SortIcon from './components/SortIcon.vue';
|
|
255
255
|
import TriangleIcon from './components/TriangleIcon.vue';
|
|
256
|
-
import {
|
|
256
|
+
import {
|
|
257
|
+
CELL_KEY_SEPARATE,
|
|
258
|
+
DEFAULT_ROW_ACTIVE_CONFIG,
|
|
259
|
+
DEFAULT_ROW_HEIGHT,
|
|
260
|
+
DEFAULT_SMOOTH_SCROLL,
|
|
261
|
+
DEFAULT_SORT_CONFIG,
|
|
262
|
+
IS_LEGACY_MODE,
|
|
263
|
+
} from './const';
|
|
257
264
|
import {
|
|
258
265
|
AutoRowHeightConfig,
|
|
259
266
|
ColResizableConfig,
|
|
@@ -264,6 +271,7 @@ import {
|
|
|
264
271
|
Order,
|
|
265
272
|
PrivateRowDT,
|
|
266
273
|
PrivateStkTableColumn,
|
|
274
|
+
RowActiveOption,
|
|
267
275
|
SeqConfig,
|
|
268
276
|
SortConfig,
|
|
269
277
|
SortOption,
|
|
@@ -328,8 +336,10 @@ const props = withDefaults(
|
|
|
328
336
|
/** 是否高亮鼠标悬浮的行 */
|
|
329
337
|
rowHover?: boolean;
|
|
330
338
|
/** 是否高亮选中的行 */
|
|
331
|
-
rowActive?: boolean
|
|
332
|
-
/**
|
|
339
|
+
rowActive?: boolean | RowActiveOption<DT>;
|
|
340
|
+
/**
|
|
341
|
+
* @deprecated
|
|
342
|
+
*/
|
|
333
343
|
rowCurrentRevokable?: boolean;
|
|
334
344
|
/** 表头行高。default = rowHeight */
|
|
335
345
|
headerRowHeight?: number | string | null;
|
|
@@ -473,10 +483,7 @@ const props = withDefaults(
|
|
|
473
483
|
autoResize: true,
|
|
474
484
|
fixedColShadow: false,
|
|
475
485
|
optimizeVue2Scroll: false,
|
|
476
|
-
sortConfig: () =>
|
|
477
|
-
emptyToBottom: false,
|
|
478
|
-
stringLocaleCompare: false,
|
|
479
|
-
}),
|
|
486
|
+
sortConfig: () => DEFAULT_SORT_CONFIG,
|
|
480
487
|
hideHeaderTitle: false,
|
|
481
488
|
highlightConfig: () => ({}),
|
|
482
489
|
seqConfig: () => ({}),
|
|
@@ -709,6 +716,19 @@ const isTreeData = computed(() => {
|
|
|
709
716
|
return props.columns.some(col => col.type === 'tree-node');
|
|
710
717
|
});
|
|
711
718
|
|
|
719
|
+
const rowActiveProp = computed<Required<RowActiveOption<DT>>>(() => {
|
|
720
|
+
const { rowActive } = props;
|
|
721
|
+
if (typeof rowActive === 'boolean') {
|
|
722
|
+
return {
|
|
723
|
+
...DEFAULT_ROW_ACTIVE_CONFIG,
|
|
724
|
+
enabled: rowActive,
|
|
725
|
+
revokable: Boolean(props.rowCurrentRevokable),
|
|
726
|
+
};
|
|
727
|
+
} else {
|
|
728
|
+
return { ...DEFAULT_ROW_ACTIVE_CONFIG, ...rowActive };
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
|
|
712
732
|
const dataSourceCopy = shallowRef<DT[]>([]);
|
|
713
733
|
|
|
714
734
|
const rowKeyGenComputed = computed(() => {
|
|
@@ -749,7 +769,8 @@ const SRBRTotalHeight = computed(() => {
|
|
|
749
769
|
});
|
|
750
770
|
const SRBRBottomHeight = computed(() => {
|
|
751
771
|
if (!isSRBRActive.value || !props.virtual) return 0;
|
|
752
|
-
|
|
772
|
+
const { containerHeight, rowHeight } = virtualScroll.value;
|
|
773
|
+
return (containerHeight - tableHeaderHeight.value) % rowHeight;
|
|
753
774
|
});
|
|
754
775
|
|
|
755
776
|
const rowKeyGenCache = new WeakMap();
|
|
@@ -788,7 +809,7 @@ const {
|
|
|
788
809
|
updateHoverMergedCells,
|
|
789
810
|
activeMergedCells,
|
|
790
811
|
updateActiveMergedCells,
|
|
791
|
-
} = useMergeCells({
|
|
812
|
+
} = useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
|
|
792
813
|
|
|
793
814
|
const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeadersForCalc });
|
|
794
815
|
|
|
@@ -1131,8 +1152,8 @@ function onColumnSort(col: StkTableColumn<DT> | undefined | null, click = true,
|
|
|
1131
1152
|
sortOrderIndex.value = sortOrderIndex.value % 3;
|
|
1132
1153
|
|
|
1133
1154
|
let order = sortSwitchOrder[sortOrderIndex.value];
|
|
1134
|
-
const sortConfig = { ...props.sortConfig, ...col.sortConfig };
|
|
1135
|
-
const defaultSort = sortConfig
|
|
1155
|
+
const sortConfig: SortConfig<any> = { ...DEFAULT_SORT_CONFIG, ...props.sortConfig, ...col.sortConfig };
|
|
1156
|
+
const { defaultSort } = sortConfig;
|
|
1136
1157
|
const colKeyGenValue = colKeyGen.value;
|
|
1137
1158
|
|
|
1138
1159
|
if (!order && defaultSort) {
|
|
@@ -1158,34 +1179,31 @@ function onColumnSort(col: StkTableColumn<DT> | undefined | null, click = true,
|
|
|
1158
1179
|
}
|
|
1159
1180
|
}
|
|
1160
1181
|
}
|
|
1182
|
+
let dataSourceTemp: any[] = props.dataSource.slice();
|
|
1161
1183
|
if (!props.sortRemote || options.force) {
|
|
1162
1184
|
const sortOption = col || defaultSort;
|
|
1163
1185
|
if (sortOption) {
|
|
1164
|
-
|
|
1186
|
+
dataSourceTemp = tableSort(sortOption, order, dataSourceTemp, sortConfig);
|
|
1187
|
+
dataSourceCopy.value = isTreeData.value ? flatTreeData(dataSourceTemp) : dataSourceTemp;
|
|
1165
1188
|
}
|
|
1166
1189
|
}
|
|
1167
|
-
//
|
|
1190
|
+
// only emit sort-change event when click
|
|
1168
1191
|
if (click || options.emit) {
|
|
1169
|
-
emits('sort-change', col, order, toRaw(
|
|
1192
|
+
emits('sort-change', col, order, toRaw(dataSourceTemp), sortConfig);
|
|
1170
1193
|
}
|
|
1171
1194
|
}
|
|
1172
1195
|
|
|
1173
1196
|
function onRowClick(e: MouseEvent, row: DT, rowIndex: number) {
|
|
1174
1197
|
emits('row-click', e, row, { rowIndex });
|
|
1198
|
+
if (rowActiveProp.value.disabled?.(row)) return;
|
|
1175
1199
|
const isCurrentRow = props.rowKey ? currentRowKey.value === rowKeyGen(row) : currentRow.value === row;
|
|
1176
1200
|
if (isCurrentRow) {
|
|
1177
|
-
if (!
|
|
1178
|
-
// 不可取消
|
|
1201
|
+
if (!rowActiveProp.value.revokable) {
|
|
1179
1202
|
return;
|
|
1180
1203
|
}
|
|
1181
|
-
|
|
1182
|
-
currentRow.value = void 0;
|
|
1183
|
-
currentRowKey.value = void 0;
|
|
1184
|
-
updateActiveMergedCells(true);
|
|
1204
|
+
setCurrentRow(void 0, { silent: true });
|
|
1185
1205
|
} else {
|
|
1186
|
-
|
|
1187
|
-
currentRowKey.value = rowKeyGen(row);
|
|
1188
|
-
updateActiveMergedCells();
|
|
1206
|
+
setCurrentRow(row, { silent: true });
|
|
1189
1207
|
}
|
|
1190
1208
|
emits('current-change', e, row, { select: !isCurrentRow });
|
|
1191
1209
|
}
|
|
@@ -1391,27 +1409,47 @@ function onTrMouseLeave(e: MouseEvent) {
|
|
|
1391
1409
|
* 选中一行
|
|
1392
1410
|
* @param {string} rowKeyOrRow selected rowKey, undefined to unselect
|
|
1393
1411
|
* @param {boolean} option.silent if set true not emit `current-change`. default:false
|
|
1412
|
+
* @param {boolean} option.deep if set true, deep search in children. default:false
|
|
1394
1413
|
*/
|
|
1395
|
-
function setCurrentRow(rowKeyOrRow: string | undefined | DT, option = { silent: false }) {
|
|
1396
|
-
if (!dataSourceCopy.value.length) return;
|
|
1414
|
+
function setCurrentRow(rowKeyOrRow: string | undefined | DT, option: { silent?: boolean; deep?: boolean } = { silent: false, deep: false }) {
|
|
1397
1415
|
const select = rowKeyOrRow !== void 0;
|
|
1416
|
+
const currentRowTemp = currentRow.value;
|
|
1398
1417
|
if (!select) {
|
|
1399
1418
|
currentRow.value = void 0;
|
|
1400
1419
|
currentRowKey.value = void 0;
|
|
1420
|
+
updateActiveMergedCells(true);
|
|
1401
1421
|
} else if (typeof rowKeyOrRow === 'string') {
|
|
1402
|
-
const
|
|
1422
|
+
const findRowByKey = (data: DT[], key: string): DT | null => {
|
|
1423
|
+
for (let i = 0; i < data.length; i++) {
|
|
1424
|
+
const item = data[i];
|
|
1425
|
+
if (rowKeyGen(item) === key) {
|
|
1426
|
+
return item;
|
|
1427
|
+
}
|
|
1428
|
+
if (option.deep && item.children?.length) {
|
|
1429
|
+
const found = findRowByKey(item.children, key);
|
|
1430
|
+
if (found) {
|
|
1431
|
+
return found;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
return null;
|
|
1436
|
+
};
|
|
1437
|
+
|
|
1438
|
+
currentRowKey.value = rowKeyOrRow;
|
|
1439
|
+
updateActiveMergedCells(false, currentRowKey.value);
|
|
1440
|
+
const row = findRowByKey(dataSourceCopy.value || [], rowKeyOrRow);
|
|
1403
1441
|
if (!row) {
|
|
1404
1442
|
console.warn('setCurrentRow failed.rowKey:', rowKeyOrRow);
|
|
1405
1443
|
return;
|
|
1406
1444
|
}
|
|
1407
1445
|
currentRow.value = row;
|
|
1408
|
-
currentRowKey.value = rowKeyOrRow;
|
|
1409
1446
|
} else {
|
|
1410
1447
|
currentRow.value = rowKeyOrRow;
|
|
1411
1448
|
currentRowKey.value = rowKeyGen(rowKeyOrRow);
|
|
1449
|
+
updateActiveMergedCells(false, currentRowKey.value);
|
|
1412
1450
|
}
|
|
1413
1451
|
if (!option.silent) {
|
|
1414
|
-
emits('current-change', /** no Event */ null, currentRow.value, { select });
|
|
1452
|
+
emits('current-change', /** no Event */ null, select ? currentRow.value : currentRowTemp, { select });
|
|
1415
1453
|
}
|
|
1416
1454
|
}
|
|
1417
1455
|
|
|
@@ -1447,7 +1485,6 @@ function setSorter(colKey: string, order: Order, option: { sortOption?: SortOpti
|
|
|
1447
1485
|
const colKeyGenValue = colKeyGen.value;
|
|
1448
1486
|
|
|
1449
1487
|
if (newOption.sort && dataSourceCopy.value?.length) {
|
|
1450
|
-
// 如果表格有数据,则进行排序
|
|
1451
1488
|
const column = newOption.sortOption || tableHeaderLast.value.find(it => colKeyGenValue(it) === sortCol.value);
|
|
1452
1489
|
if (column) onColumnSort(column, false, { force: option.force ?? true, emit: !newOption.silent });
|
|
1453
1490
|
else console.warn('Can not find column by key:', sortCol.value);
|
package/src/StkTable/const.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RowActiveOption, SortConfig } from './types';
|
|
1
2
|
import { getBrowsersVersion } from './utils';
|
|
2
3
|
|
|
3
4
|
export const DEFAULT_COL_WIDTH = '100';
|
|
@@ -33,5 +34,17 @@ export const STK_ID_PREFIX = 'stk';
|
|
|
33
34
|
/** expanded row key prefix */
|
|
34
35
|
export const EXPANDED_ROW_KEY_PREFIX = 'expanded-';
|
|
35
36
|
|
|
36
|
-
/** cell key
|
|
37
|
+
/** cell key split str */
|
|
37
38
|
export const CELL_KEY_SEPARATE = '--';
|
|
39
|
+
|
|
40
|
+
export const DEFAULT_SORT_CONFIG = {
|
|
41
|
+
emptyToBottom: false,
|
|
42
|
+
stringLocaleCompare: false,
|
|
43
|
+
sortChildren: false,
|
|
44
|
+
} satisfies SortConfig<any>;
|
|
45
|
+
|
|
46
|
+
export const DEFAULT_ROW_ACTIVE_CONFIG: Required<RowActiveOption<any>> = {
|
|
47
|
+
enabled: false,
|
|
48
|
+
disabled: () => false,
|
|
49
|
+
revokable: false,
|
|
50
|
+
};
|
|
@@ -88,7 +88,7 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
88
88
|
/** 排序方式。按数字/字符串 */
|
|
89
89
|
sortType?: 'number' | 'string';
|
|
90
90
|
/** 配置当前列的排序规则 */
|
|
91
|
-
sortConfig?:
|
|
91
|
+
sortConfig?: Omit<SortConfig<T>, 'defaultSort'>;
|
|
92
92
|
/** 固定列 */
|
|
93
93
|
fixed?: 'left' | 'right' | null;
|
|
94
94
|
/**
|
|
@@ -176,17 +176,17 @@ export type UniqKeyFun = (param: any) => UniqKey;
|
|
|
176
176
|
export type UniqKeyProp = UniqKey | UniqKeyFun;
|
|
177
177
|
|
|
178
178
|
export type SortConfig<T extends Record<string, any>> = {
|
|
179
|
-
/** 空值始终排在列表末尾 */
|
|
180
|
-
emptyToBottom?: boolean;
|
|
181
179
|
/**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
180
|
+
* 1. trigger when init
|
|
181
|
+
* 2. trigger when sort direction is null
|
|
184
182
|
*/
|
|
185
183
|
defaultSort?: {
|
|
186
184
|
/**
|
|
187
|
-
*
|
|
185
|
+
* colKey
|
|
186
|
+
*
|
|
187
|
+
* if set `props.colKey`
|
|
188
188
|
*
|
|
189
|
-
*
|
|
189
|
+
* default: StkTableColumn<T>['dataIndex']
|
|
190
190
|
*/
|
|
191
191
|
key?: StkTableColumn<T>['key'];
|
|
192
192
|
dataIndex: StkTableColumn<T>['dataIndex'];
|
|
@@ -194,14 +194,22 @@ export type SortConfig<T extends Record<string, any>> = {
|
|
|
194
194
|
sortField?: StkTableColumn<T>['sortField'];
|
|
195
195
|
sortType?: StkTableColumn<T>['sortType'];
|
|
196
196
|
sorter?: StkTableColumn<T>['sorter'];
|
|
197
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* whether to disable trigger`sort-change` event. default: false
|
|
199
|
+
*/
|
|
198
200
|
silent?: boolean;
|
|
199
201
|
};
|
|
202
|
+
/** empty value always sort to bottom */
|
|
203
|
+
emptyToBottom?: boolean;
|
|
200
204
|
/**
|
|
201
205
|
* string sort if use `String.prototype.localCompare`
|
|
202
206
|
* default: false
|
|
203
207
|
*/
|
|
204
208
|
stringLocaleCompare?: boolean;
|
|
209
|
+
/**
|
|
210
|
+
* whether to sort children when sort current column. default: false
|
|
211
|
+
*/
|
|
212
|
+
sortChildren?: boolean;
|
|
205
213
|
};
|
|
206
214
|
|
|
207
215
|
/** th td type */
|
|
@@ -242,7 +250,6 @@ export type DragRowConfig = {
|
|
|
242
250
|
// disabled?: (row: T, rowIndex: number) => boolean;
|
|
243
251
|
};
|
|
244
252
|
|
|
245
|
-
/** 树形配置 */
|
|
246
253
|
export type TreeConfig = {
|
|
247
254
|
// childrenField?: string;
|
|
248
255
|
defaultExpandAll?: boolean;
|
|
@@ -253,13 +260,13 @@ export type TreeConfig = {
|
|
|
253
260
|
/** header drag config */
|
|
254
261
|
export type HeaderDragConfig<DT extends Record<string, any> = any> = {
|
|
255
262
|
/**
|
|
256
|
-
*
|
|
257
|
-
* - none
|
|
258
|
-
* - insert -
|
|
259
|
-
* - swap
|
|
263
|
+
* col switch mode
|
|
264
|
+
* - none
|
|
265
|
+
* - insert - (default)
|
|
266
|
+
* - swap
|
|
260
267
|
*/
|
|
261
268
|
mode?: 'none' | 'insert' | 'swap';
|
|
262
|
-
/**
|
|
269
|
+
/** disabled drag col */
|
|
263
270
|
disabled?: (col: StkTableColumn<DT>) => boolean;
|
|
264
271
|
};
|
|
265
272
|
|
|
@@ -277,3 +284,11 @@ export type RowKeyGen = (row: any) => UniqKey;
|
|
|
277
284
|
export type ColKeyGen = ComputedRef<(col: StkTableColumn<any>) => UniqKey>;
|
|
278
285
|
|
|
279
286
|
export type CellKeyGen = (row: any, col: StkTableColumn<any>) => string;
|
|
287
|
+
|
|
288
|
+
export type RowActiveOption<DT> = {
|
|
289
|
+
enabled?: boolean;
|
|
290
|
+
/** disabled row active */
|
|
291
|
+
disabled?: (row: DT) => boolean;
|
|
292
|
+
/** current row again click can revoke active */
|
|
293
|
+
revokable?: boolean;
|
|
294
|
+
};
|
|
@@ -64,7 +64,8 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
|
|
|
64
64
|
/** 键盘按下事件 */
|
|
65
65
|
function handleKeydown(e: KeyboardEvent) {
|
|
66
66
|
if (!virtual_on.value) return; // 非虚拟滚动使用浏览器默认滚动
|
|
67
|
-
|
|
67
|
+
const keyCode = e.code;
|
|
68
|
+
if (!ScrollCodesValues.includes(keyCode as any)) return;
|
|
68
69
|
if (!isMouseOver) return; // 不悬浮还是要触发键盘事件的
|
|
69
70
|
e.preventDefault(); // 不触发键盘默认的箭头事件
|
|
70
71
|
|
|
@@ -76,22 +77,21 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
|
|
|
76
77
|
const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
|
|
77
78
|
/** 表体的page */
|
|
78
79
|
const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
|
|
79
|
-
|
|
80
|
-
if (e.code === ScrollCodes.ArrowUp) {
|
|
80
|
+
if (keyCode=== ScrollCodes.ArrowUp) {
|
|
81
81
|
scrollTo(scrollTop - rowHeight, null);
|
|
82
|
-
} else if (
|
|
82
|
+
} else if (keyCode=== ScrollCodes.ArrowRight) {
|
|
83
83
|
scrollTo(null, scrollLeft + 50);
|
|
84
|
-
} else if (
|
|
84
|
+
} else if (keyCode=== ScrollCodes.ArrowDown) {
|
|
85
85
|
scrollTo(scrollTop + rowHeight, null);
|
|
86
|
-
} else if (
|
|
86
|
+
} else if (keyCode=== ScrollCodes.ArrowLeft) {
|
|
87
87
|
scrollTo(null, scrollLeft - 50);
|
|
88
|
-
} else if (
|
|
88
|
+
} else if (keyCode=== ScrollCodes.PageUp) {
|
|
89
89
|
scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
|
|
90
|
-
} else if (
|
|
90
|
+
} else if (keyCode=== ScrollCodes.PageDown) {
|
|
91
91
|
scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
|
|
92
|
-
} else if (
|
|
92
|
+
} else if (keyCode=== ScrollCodes.Home) {
|
|
93
93
|
scrollTo(0, null);
|
|
94
|
-
} else if (
|
|
94
|
+
} else if (keyCode=== ScrollCodes.End) {
|
|
95
95
|
scrollTo(scrollHeight, null);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
import { ref, ShallowRef, watch } from 'vue';
|
|
2
|
-
import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
|
|
1
|
+
import { Ref, ref, ShallowRef, watch } from 'vue';
|
|
2
|
+
import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowActiveOption, RowKeyGen, UniqKey } from './types';
|
|
3
3
|
import { pureCellKeyGen } from './utils';
|
|
4
4
|
type Options = {
|
|
5
|
-
|
|
5
|
+
rowActiveProp: Ref<RowActiveOption<any>>;
|
|
6
6
|
tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
|
|
7
7
|
rowKeyGen: RowKeyGen;
|
|
8
8
|
colKeyGen: ColKeyGen;
|
|
9
9
|
virtual_dataSourcePart: ShallowRef<any[]>;
|
|
10
|
-
}
|
|
11
|
-
export function useMergeCells({
|
|
12
|
-
props,
|
|
13
|
-
tableHeaderLast,
|
|
14
|
-
rowKeyGen,
|
|
15
|
-
colKeyGen,
|
|
16
|
-
virtual_dataSourcePart,
|
|
17
|
-
}:Options ) {
|
|
10
|
+
};
|
|
11
|
+
export function useMergeCells({ rowActiveProp, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart }: Options) {
|
|
18
12
|
/**
|
|
19
13
|
* which cell need be hidden
|
|
20
14
|
* - key: rowKey
|
|
@@ -33,13 +27,12 @@ export function useMergeCells({
|
|
|
33
27
|
/** click current row , which rowspan cells should be highlight */
|
|
34
28
|
const activeMergedCells = ref(new Set<string>());
|
|
35
29
|
|
|
36
|
-
|
|
37
30
|
watch([virtual_dataSourcePart, tableHeaderLast], () => {
|
|
38
31
|
hiddenCellMap.value = {};
|
|
39
32
|
hoverRowMap.value = {};
|
|
40
33
|
});
|
|
41
34
|
|
|
42
|
-
/**
|
|
35
|
+
/**
|
|
43
36
|
* abstract the logic of hiding cells
|
|
44
37
|
*/
|
|
45
38
|
function hideCells(rowKey: UniqKey, startIndex: number, count: number, isSelfRow = false, mergeCellKey: string) {
|
|
@@ -84,14 +77,14 @@ export function useMergeCells({
|
|
|
84
77
|
if (colspan === 1 && rowspan === 1) return;
|
|
85
78
|
|
|
86
79
|
const rowKey = rowKeyGen(row);
|
|
87
|
-
|
|
80
|
+
|
|
88
81
|
const colKey = colKeyGen.value(col);
|
|
89
82
|
const curColIndex = tableHeaderLast.value.findIndex(item => colKeyGen.value(item) === colKey);
|
|
90
83
|
const curRowIndex = virtual_dataSourcePart.value.findIndex(item => rowKeyGen(item) === rowKey);
|
|
91
84
|
const mergedCellKey = pureCellKeyGen(rowKey, colKey);
|
|
92
85
|
|
|
93
86
|
if (curRowIndex === -1) return;
|
|
94
|
-
|
|
87
|
+
|
|
95
88
|
for (let i = curRowIndex; i < curRowIndex + rowspan; i++) {
|
|
96
89
|
const row = virtual_dataSourcePart.value[i];
|
|
97
90
|
if (!row) break;
|
|
@@ -106,13 +99,13 @@ export function useMergeCells({
|
|
|
106
99
|
hoverMergedCells.value = set || new Set();
|
|
107
100
|
}
|
|
108
101
|
|
|
109
|
-
function updateActiveMergedCells(clear?: boolean) {
|
|
110
|
-
if (!
|
|
102
|
+
function updateActiveMergedCells(clear?: boolean, rowKey?: UniqKey) {
|
|
103
|
+
if (!rowActiveProp.value.enabled) return;
|
|
111
104
|
if (clear) {
|
|
112
105
|
activeMergedCells.value.clear();
|
|
113
|
-
|
|
114
|
-
activeMergedCells.value = new Set(hoverMergedCells.value);
|
|
106
|
+
return;
|
|
115
107
|
}
|
|
108
|
+
activeMergedCells.value = (rowKey !== void 0 && hoverRowMap.value[rowKey]) || new Set(hoverMergedCells.value);
|
|
116
109
|
}
|
|
117
110
|
|
|
118
111
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CELL_KEY_SEPARATE } from '../const';
|
|
1
|
+
import { CELL_KEY_SEPARATE, DEFAULT_SORT_CONFIG } from '../const';
|
|
2
2
|
import { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKey } from '../types';
|
|
3
3
|
|
|
4
4
|
/** 是否空值 */
|
|
@@ -158,19 +158,28 @@ export function tableSort<T extends Record<string, any>>(
|
|
|
158
158
|
): T[] {
|
|
159
159
|
if (!dataSource?.length || !sortOption) return dataSource || [];
|
|
160
160
|
|
|
161
|
-
sortConfig = {
|
|
161
|
+
sortConfig = { ...DEFAULT_SORT_CONFIG, ...sortConfig };
|
|
162
162
|
let targetDataSource = dataSource.slice();
|
|
163
163
|
let sortField = sortOption.sortField || sortOption.dataIndex;
|
|
164
|
+
const { defaultSort, stringLocaleCompare, emptyToBottom, sortChildren } = sortConfig;
|
|
164
165
|
|
|
165
|
-
if (!order &&
|
|
166
|
+
if (!order && defaultSort) {
|
|
166
167
|
// 默认排序
|
|
167
|
-
order =
|
|
168
|
-
sortField =
|
|
168
|
+
order = defaultSort.order;
|
|
169
|
+
sortField = defaultSort.dataIndex;
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
if (typeof sortOption.sorter === 'function') {
|
|
172
173
|
const customSorterData = sortOption.sorter(targetDataSource, { order, column: sortOption });
|
|
173
174
|
if (customSorterData) targetDataSource = customSorterData;
|
|
175
|
+
|
|
176
|
+
// 如果开启了子节点排序且使用了自定义排序器,递归排序children
|
|
177
|
+
if (sortChildren) {
|
|
178
|
+
targetDataSource.forEach(item => {
|
|
179
|
+
if (!item.children?.length) return;
|
|
180
|
+
(item as any).children = tableSort(sortOption, order, item.children, sortConfig);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
174
183
|
} else if (order) {
|
|
175
184
|
let { sortType } = sortOption;
|
|
176
185
|
if (!sortType) sortType = typeof dataSource[0][sortField] as 'number' | 'string';
|
|
@@ -179,15 +188,19 @@ export function tableSort<T extends Record<string, any>>(
|
|
|
179
188
|
const [valueArr, emptyArr] = separatedData(sortOption, targetDataSource, isNumber);
|
|
180
189
|
|
|
181
190
|
if (order === 'asc') {
|
|
182
|
-
valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber,
|
|
191
|
+
valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, stringLocaleCompare));
|
|
183
192
|
} else {
|
|
184
|
-
valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber,
|
|
193
|
+
valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, stringLocaleCompare));
|
|
185
194
|
}
|
|
186
195
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
196
|
+
targetDataSource = order === 'desc' || emptyToBottom ? valueArr.concat(emptyArr) : emptyArr.concat(valueArr);
|
|
197
|
+
|
|
198
|
+
// 递归排序子节点
|
|
199
|
+
if (sortChildren) {
|
|
200
|
+
targetDataSource.forEach(item => {
|
|
201
|
+
if (!item.children?.length) return;
|
|
202
|
+
(item as any).children = tableSort(sortOption, order, item.children, sortConfig);
|
|
203
|
+
});
|
|
191
204
|
}
|
|
192
205
|
}
|
|
193
206
|
return targetDataSource;
|