stk-table-vue 0.2.3 → 0.2.5
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 +18 -2
- package/lib/src/StkTable/StkTable.vue.d.ts +10 -1
- package/lib/src/StkTable/index.d.ts +1 -0
- package/lib/src/StkTable/types/index.d.ts +5 -0
- package/lib/src/StkTable/useFixedStyle.d.ts +3 -3
- package/lib/src/StkTable/useVirtualScroll.d.ts +3 -2
- package/lib/src/StkTable/utils.d.ts +3 -1
- package/lib/stk-table-vue.js +165 -91
- package/package.json +60 -60
- package/src/StkTable/StkTable.vue +41 -17
- package/src/StkTable/types/index.ts +5 -0
- package/src/StkTable/useFixedStyle.ts +49 -28
- package/src/StkTable/useHighlight.ts +3 -3
- package/src/StkTable/useKeyboardArrowScroll.ts +8 -4
- package/src/StkTable/useVirtualScroll.ts +42 -11
- package/src/StkTable/utils.ts +66 -41
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@ Vue3 简易虚拟滚动表格。用于实时数据展示,新数据行高亮渐
|
|
|
4
4
|
|
|
5
5
|
Vue2.7支持引入源码(**ts**)使用。
|
|
6
6
|
|
|
7
|
+
repo:
|
|
8
|
+
- [Github](https://github.com/ja-plus/stk-table-vue)
|
|
9
|
+
- [Gitee](https://gitee.com/japlus/stk-table-vue) 🇨🇳
|
|
10
|
+
|
|
7
11
|
## Bug TODO:
|
|
8
12
|
* [x] props.dataSource 为 shallowRef 时,高亮行不生效。(bug:2024.02.21)(resolved:0.2.3)
|
|
9
13
|
|
|
@@ -18,7 +22,7 @@ Vue2.7支持引入源码(**ts**)使用。
|
|
|
18
22
|
- [] sticky column 动态计算阴影位置。
|
|
19
23
|
* [] 列筛选。
|
|
20
24
|
* [x] 斑马纹。
|
|
21
|
-
- [] 虚拟滚动斑马纹。
|
|
25
|
+
- [x] 虚拟滚动斑马纹。
|
|
22
26
|
* [x] 表头拖动更改顺序。
|
|
23
27
|
* [x] 表头拖动调整列宽。
|
|
24
28
|
* [x] 排序
|
|
@@ -33,10 +37,10 @@ Vue2.7支持引入源码(**ts**)使用。
|
|
|
33
37
|
* 鼠标悬浮在表格上,键盘滚动虚拟表格。
|
|
34
38
|
- [x] 键盘 `ArrowUp`/`ArrowDown`/`ArrowLeft`/`ArrowRight` 按键支持。
|
|
35
39
|
- [x] 键盘 `PageUp`/ `PageDown` 按键支持。
|
|
36
|
-
* [] 不传row-key 时,自动按序号生成id。
|
|
37
40
|
* [] 非虚拟滚动时,大数据分批加载。
|
|
38
41
|
* [x] vue2.7支持(引入源码使用)。
|
|
39
42
|
- [x] `props.optimizeVue2Scroll` 优化vue2虚拟滚动流畅度。
|
|
43
|
+
* [] `props.emptyCellText` 支持传入函数。
|
|
40
44
|
|
|
41
45
|
|
|
42
46
|
## Usage
|
|
@@ -188,7 +192,14 @@ export type StkProps = {
|
|
|
188
192
|
dataIndex: keyof T;
|
|
189
193
|
order: Order;
|
|
190
194
|
};
|
|
195
|
+
/**
|
|
196
|
+
* string排序是否使用 String.prototype.localCompare
|
|
197
|
+
* 默认true (历史设计问题,为了兼容,默认true)
|
|
198
|
+
*/
|
|
199
|
+
stringLocaleCompare?: boolean;
|
|
191
200
|
},
|
|
201
|
+
/** 隐藏头部title。可传入dataIndex数组 */
|
|
202
|
+
hideHeaderTitle?: boolean | string[];
|
|
192
203
|
};
|
|
193
204
|
```
|
|
194
205
|
#### Emits
|
|
@@ -404,3 +415,8 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
404
415
|
]
|
|
405
416
|
</script>
|
|
406
417
|
```
|
|
418
|
+
|
|
419
|
+
## Special Example
|
|
420
|
+
### 鼠标悬浮表头时,不展示title
|
|
421
|
+
* 将 `StkTableColumn` 中的 `title` 字段置为 "" 空字符串。这样th中就没有title了。
|
|
422
|
+
* 使用 `StkTableColumn` 中的 `customHeaderCell` 属性中,自定义表头渲染。
|
|
@@ -13,7 +13,7 @@ declare function setCurrentRow(rowKey: string, option?: {
|
|
|
13
13
|
* 设置表头排序状态
|
|
14
14
|
* @param dataIndex 列字段
|
|
15
15
|
* @param order 正序倒序
|
|
16
|
-
* @param option.sortOption
|
|
16
|
+
* @param option.sortOption 指定排序参数。同 StkTableColumn 中排序相关字段。建议从columns中find得到。
|
|
17
17
|
* @param option.sort 是否触发排序-默认true
|
|
18
18
|
* @param option.silent 是否禁止触发回调-默认true
|
|
19
19
|
*/
|
|
@@ -113,6 +113,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
113
113
|
optimizeVue2Scroll?: boolean | undefined;
|
|
114
114
|
/** 排序配置 */
|
|
115
115
|
sortConfig?: SortConfig<any> | undefined;
|
|
116
|
+
/** 隐藏头部title。可传入dataIndex数组 */
|
|
117
|
+
hideHeaderTitle?: boolean | string[] | undefined;
|
|
116
118
|
}>, {
|
|
117
119
|
width: string;
|
|
118
120
|
fixedMode: boolean;
|
|
@@ -146,7 +148,9 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
146
148
|
optimizeVue2Scroll: boolean;
|
|
147
149
|
sortConfig: () => {
|
|
148
150
|
emptyToBottom: boolean;
|
|
151
|
+
stringLocaleCompare: boolean;
|
|
149
152
|
};
|
|
153
|
+
hideHeaderTitle: boolean;
|
|
150
154
|
}>, {
|
|
151
155
|
/** 初始化横向纵向虚拟滚动 */
|
|
152
156
|
initVirtualScroll: (height?: number | undefined) => void;
|
|
@@ -269,6 +273,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
269
273
|
optimizeVue2Scroll?: boolean | undefined;
|
|
270
274
|
/** 排序配置 */
|
|
271
275
|
sortConfig?: SortConfig<any> | undefined;
|
|
276
|
+
/** 隐藏头部title。可传入dataIndex数组 */
|
|
277
|
+
hideHeaderTitle?: boolean | string[] | undefined;
|
|
272
278
|
}>, {
|
|
273
279
|
width: string;
|
|
274
280
|
fixedMode: boolean;
|
|
@@ -302,7 +308,9 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
302
308
|
optimizeVue2Scroll: boolean;
|
|
303
309
|
sortConfig: () => {
|
|
304
310
|
emptyToBottom: boolean;
|
|
311
|
+
stringLocaleCompare: boolean;
|
|
305
312
|
};
|
|
313
|
+
hideHeaderTitle: boolean;
|
|
306
314
|
}>>> & {
|
|
307
315
|
onScroll?: ((ev: Event, data: {
|
|
308
316
|
startIndex: number;
|
|
@@ -353,6 +361,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
353
361
|
fixedColShadow: boolean;
|
|
354
362
|
optimizeVue2Scroll: boolean;
|
|
355
363
|
sortConfig: SortConfig<any>;
|
|
364
|
+
hideHeaderTitle: boolean | string[];
|
|
356
365
|
}, {}>, {
|
|
357
366
|
tableHeader?(_: {
|
|
358
367
|
col: StkTableColumn<any>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { CSSProperties, Ref } from 'vue';
|
|
2
2
|
import { StkTableColumn } from './types';
|
|
3
3
|
import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
4
|
-
type Options = {
|
|
4
|
+
type Options<T extends Record<string, any>> = {
|
|
5
5
|
props: any;
|
|
6
|
-
|
|
6
|
+
tableHeaders: Ref<StkTableColumn<T>[][]>;
|
|
7
7
|
virtualScroll: Ref<VirtualScrollStore>;
|
|
8
8
|
virtualScrollX: Ref<VirtualScrollXStore>;
|
|
9
9
|
virtualX_on: Ref<boolean>;
|
|
@@ -14,7 +14,7 @@ type Options = {
|
|
|
14
14
|
* @param param0
|
|
15
15
|
* @returns
|
|
16
16
|
*/
|
|
17
|
-
export declare function useFixedStyle({ props,
|
|
17
|
+
export declare function useFixedStyle<DT extends Record<string, any>>({ props, tableHeaders, virtualScroll, virtualScrollX, virtualX_on, virtualX_offsetRight, }: Options<DT>): {
|
|
18
18
|
getFixedStyle: (tagType: 1 | 2, col: StkTableColumn<any>, depth?: number) => CSSProperties;
|
|
19
19
|
};
|
|
20
20
|
export {};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Ref, ShallowRef } from 'vue';
|
|
2
2
|
import { StkTableColumn } from './types';
|
|
3
3
|
type Option<DT extends Record<string, any>> = {
|
|
4
|
-
tableContainer: Ref<HTMLElement | undefined>;
|
|
5
4
|
props: any;
|
|
5
|
+
tableContainer: Ref<HTMLElement | undefined>;
|
|
6
6
|
dataSourceCopy: ShallowRef<DT[]>;
|
|
7
7
|
tableHeaderLast: Ref<StkTableColumn<DT>[]>;
|
|
8
|
+
tableHeaders: Ref<StkTableColumn<DT>[][]>;
|
|
8
9
|
};
|
|
9
10
|
/** 暂存纵向虚拟滚动的数据 */
|
|
10
11
|
export type VirtualScrollStore = {
|
|
@@ -41,7 +42,7 @@ export type VirtualScrollXStore = {
|
|
|
41
42
|
* @param param0
|
|
42
43
|
* @returns
|
|
43
44
|
*/
|
|
44
|
-
export declare function useVirtualScroll<DT extends Record<string, any>>({ props, tableContainer, dataSourceCopy, tableHeaderLast }: Option<DT>): {
|
|
45
|
+
export declare function useVirtualScroll<DT extends Record<string, any>>({ props, tableContainer, dataSourceCopy, tableHeaderLast, tableHeaders, }: Option<DT>): {
|
|
45
46
|
virtualScroll: Ref<{
|
|
46
47
|
containerHeight: number;
|
|
47
48
|
pageSize: number;
|
|
@@ -8,7 +8,7 @@ import { Order, SortConfig, SortOption, SortState, StkTableColumn } from './type
|
|
|
8
8
|
* @param newItem 要插入的数据
|
|
9
9
|
* @param targetArray 表格数据
|
|
10
10
|
*/
|
|
11
|
-
export declare function insertToOrderedArray<T extends object>(sortState: SortState<keyof T>, newItem: any, targetArray: T[]): T[];
|
|
11
|
+
export declare function insertToOrderedArray<T extends object>(sortState: SortState<keyof T>, newItem: any, targetArray: T[], sortConfig?: SortConfig<T>): T[];
|
|
12
12
|
/**
|
|
13
13
|
* 表格排序抽离
|
|
14
14
|
* 可以在组件外部自己实现表格排序,组件配置remote,使表格不排序。
|
|
@@ -25,3 +25,5 @@ export declare function tableSort<T extends Record<string, any>>(sortOption: Sor
|
|
|
25
25
|
export declare function howDeepTheHeader(arr: StkTableColumn<any>[], level?: number): number;
|
|
26
26
|
/** 获取列宽 */
|
|
27
27
|
export declare function getColWidth(col: StkTableColumn<any> | null): number;
|
|
28
|
+
/** 获取列宽配置。用于支持列宽配置数字 */
|
|
29
|
+
export declare function getColWidthStr(col: StkTableColumn<any> | null | undefined, key?: 'width' | 'minWidth' | 'maxWidth'): string | undefined;
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -70,23 +70,35 @@ function useAutoResize({ tableContainer, initVirtualScroll, props, debounceMs })
|
|
|
70
70
|
}, debounceMs);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
function
|
|
73
|
+
function isEmptyValue(val, isNumber) {
|
|
74
|
+
let isEmpty = val === null || val === "";
|
|
75
|
+
if (isNumber) {
|
|
76
|
+
isEmpty || (isEmpty = typeof val === "boolean" || Number.isNaN(+val));
|
|
77
|
+
}
|
|
78
|
+
return isEmpty;
|
|
79
|
+
}
|
|
80
|
+
function insertToOrderedArray(sortState, newItem, targetArray, sortConfig = {}) {
|
|
74
81
|
const { dataIndex, order } = sortState;
|
|
82
|
+
sortConfig = { emptyToBottom: false, ...sortConfig };
|
|
75
83
|
let { sortType } = sortState;
|
|
76
84
|
if (!sortType)
|
|
77
85
|
sortType = typeof newItem[dataIndex];
|
|
86
|
+
const isNumber = sortType === "number";
|
|
78
87
|
const data = [...targetArray];
|
|
79
88
|
if (!order) {
|
|
80
89
|
data.unshift(newItem);
|
|
81
90
|
return data;
|
|
82
91
|
}
|
|
92
|
+
if (sortConfig.emptyToBottom && isEmptyValue(data)) {
|
|
93
|
+
data.push(newItem);
|
|
94
|
+
}
|
|
83
95
|
let sIndex = 0;
|
|
84
96
|
let eIndex = data.length - 1;
|
|
85
97
|
const targetVal = newItem[dataIndex];
|
|
86
98
|
while (sIndex <= eIndex) {
|
|
87
99
|
const midIndex = Math.floor((sIndex + eIndex) / 2);
|
|
88
100
|
const midVal = data[midIndex][dataIndex];
|
|
89
|
-
const compareRes = strCompare(midVal, targetVal,
|
|
101
|
+
const compareRes = strCompare(midVal, targetVal, isNumber, sortConfig.stringLocaleCompare);
|
|
90
102
|
if (compareRes === 0) {
|
|
91
103
|
sIndex = midIndex;
|
|
92
104
|
break;
|
|
@@ -105,17 +117,21 @@ function insertToOrderedArray(sortState, newItem, targetArray) {
|
|
|
105
117
|
data.splice(sIndex, 0, newItem);
|
|
106
118
|
return data;
|
|
107
119
|
}
|
|
108
|
-
function strCompare(a, b,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return -1;
|
|
116
|
-
} else {
|
|
120
|
+
function strCompare(a, b, isNumber, localeCompare = false) {
|
|
121
|
+
let _a = a;
|
|
122
|
+
let _b = b;
|
|
123
|
+
if (isNumber) {
|
|
124
|
+
_a = +a;
|
|
125
|
+
_b = +b;
|
|
126
|
+
} else if (localeCompare) {
|
|
117
127
|
return String(a).localeCompare(b);
|
|
118
128
|
}
|
|
129
|
+
if (_a > _b)
|
|
130
|
+
return 1;
|
|
131
|
+
else if (_a === _b)
|
|
132
|
+
return 0;
|
|
133
|
+
else
|
|
134
|
+
return -1;
|
|
119
135
|
}
|
|
120
136
|
function separatedData(sortOption, targetDataSource, isNumber) {
|
|
121
137
|
const emptyArr = [];
|
|
@@ -123,10 +139,7 @@ function separatedData(sortOption, targetDataSource, isNumber) {
|
|
|
123
139
|
for (let i = 0; i < targetDataSource.length; i++) {
|
|
124
140
|
const row = targetDataSource[i];
|
|
125
141
|
const sortField = sortOption.sortField || sortOption.dataIndex;
|
|
126
|
-
|
|
127
|
-
if (isNumber) {
|
|
128
|
-
isEmpty || (isEmpty = typeof row[sortField] === "boolean" || Number.isNaN(+row[sortField]));
|
|
129
|
-
}
|
|
142
|
+
const isEmpty = isEmptyValue(row[sortField], isNumber);
|
|
130
143
|
if (isEmpty) {
|
|
131
144
|
emptyArr.push(row);
|
|
132
145
|
} else {
|
|
@@ -154,25 +167,16 @@ function tableSort(sortOption, order, dataSource, sortConfig = {}) {
|
|
|
154
167
|
if (!sortType)
|
|
155
168
|
sortType = typeof dataSource[0][sortField];
|
|
156
169
|
const [valueArr, emptyArr] = separatedData(sortOption, targetDataSource, sortType === "number");
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
targetDataSource = [...emptyArr, ...valueArr];
|
|
161
|
-
} else {
|
|
162
|
-
valueArr.sort((a, b) => +b[sortField] - +a[sortField]);
|
|
163
|
-
targetDataSource = [...valueArr, ...emptyArr];
|
|
164
|
-
}
|
|
170
|
+
const isNumber = sortType === "number";
|
|
171
|
+
if (order === "asc") {
|
|
172
|
+
valueArr.sort((a, b) => strCompare(a[sortField], b[sortField], isNumber, sortConfig.stringLocaleCompare));
|
|
165
173
|
} else {
|
|
166
|
-
|
|
167
|
-
valueArr.sort((a, b) => String(a[sortField]).localeCompare(b[sortField]));
|
|
168
|
-
targetDataSource = [...emptyArr, ...valueArr];
|
|
169
|
-
} else {
|
|
170
|
-
valueArr.sort((a, b) => String(a[sortField]).localeCompare(b[sortField]) * -1);
|
|
171
|
-
targetDataSource = [...valueArr, ...emptyArr];
|
|
172
|
-
}
|
|
174
|
+
valueArr.sort((a, b) => strCompare(b[sortField], a[sortField], isNumber, sortConfig.stringLocaleCompare));
|
|
173
175
|
}
|
|
174
|
-
if (sortConfig.emptyToBottom) {
|
|
176
|
+
if (order === "desc" || sortConfig.emptyToBottom) {
|
|
175
177
|
targetDataSource = [...valueArr, ...emptyArr];
|
|
178
|
+
} else {
|
|
179
|
+
targetDataSource = [...emptyArr, ...valueArr];
|
|
176
180
|
}
|
|
177
181
|
}
|
|
178
182
|
return targetDataSource;
|
|
@@ -188,10 +192,18 @@ function howDeepTheHeader(arr, level = 1) {
|
|
|
188
192
|
return Math.max(...levels);
|
|
189
193
|
}
|
|
190
194
|
function getColWidth(col) {
|
|
191
|
-
|
|
192
|
-
|
|
195
|
+
const val = (col == null ? void 0 : col.width) ?? Default_Col_Width;
|
|
196
|
+
if (typeof val === "number") {
|
|
197
|
+
return Math.floor(val);
|
|
193
198
|
}
|
|
194
|
-
return parseInt(
|
|
199
|
+
return parseInt(val);
|
|
200
|
+
}
|
|
201
|
+
function getColWidthStr(col, key = "width") {
|
|
202
|
+
const val = col == null ? void 0 : col[key];
|
|
203
|
+
if (typeof val === "number") {
|
|
204
|
+
return val + "px";
|
|
205
|
+
}
|
|
206
|
+
return val;
|
|
195
207
|
}
|
|
196
208
|
function useColResize({
|
|
197
209
|
tableContainer,
|
|
@@ -371,36 +383,54 @@ function useFixedCol({ props, tableHeaderLast, tableContainer }) {
|
|
|
371
383
|
updateFixedShadow
|
|
372
384
|
};
|
|
373
385
|
}
|
|
374
|
-
function useFixedStyle({
|
|
386
|
+
function useFixedStyle({
|
|
387
|
+
props,
|
|
388
|
+
tableHeaders,
|
|
389
|
+
virtualScroll,
|
|
390
|
+
virtualScrollX,
|
|
391
|
+
virtualX_on,
|
|
392
|
+
virtualX_offsetRight
|
|
393
|
+
}) {
|
|
375
394
|
const fixedColumnsPositionStore = computed(() => {
|
|
376
|
-
const
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
395
|
+
const colKeyStore = {};
|
|
396
|
+
const refStore = /* @__PURE__ */ new WeakMap();
|
|
397
|
+
tableHeaders.value.forEach((cols) => {
|
|
398
|
+
let left = 0;
|
|
399
|
+
let rightStartIndex = 0;
|
|
400
|
+
for (let i = 0; i < cols.length; i++) {
|
|
401
|
+
const item = cols[i];
|
|
402
|
+
if (item.fixed === "left") {
|
|
403
|
+
if (item.dataIndex) {
|
|
404
|
+
colKeyStore[item.dataIndex] = left;
|
|
405
|
+
} else {
|
|
406
|
+
refStore.set(item, left);
|
|
407
|
+
}
|
|
408
|
+
left += getColWidth(item);
|
|
409
|
+
}
|
|
410
|
+
if (!rightStartIndex && item.fixed === "right") {
|
|
411
|
+
rightStartIndex = i;
|
|
412
|
+
}
|
|
388
413
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
414
|
+
let right = 0;
|
|
415
|
+
for (let i = cols.length - 1; i >= rightStartIndex; i--) {
|
|
416
|
+
const item = cols[i];
|
|
417
|
+
if (item.fixed === "right") {
|
|
418
|
+
if (item.dataIndex) {
|
|
419
|
+
colKeyStore[item.dataIndex] = right;
|
|
420
|
+
} else {
|
|
421
|
+
refStore.set(item, right);
|
|
422
|
+
}
|
|
423
|
+
right += getColWidth(item);
|
|
424
|
+
}
|
|
396
425
|
}
|
|
397
|
-
}
|
|
398
|
-
return
|
|
426
|
+
});
|
|
427
|
+
return { refStore, colKeyStore };
|
|
399
428
|
});
|
|
400
429
|
function getFixedStyle(tagType, col, depth = 0) {
|
|
401
|
-
const { fixed
|
|
430
|
+
const { fixed } = col;
|
|
402
431
|
const isFixedLeft = fixed === "left";
|
|
403
432
|
const style = {};
|
|
433
|
+
const { colKeyStore, refStore } = fixedColumnsPositionStore.value;
|
|
404
434
|
if (Is_Legacy_Mode) {
|
|
405
435
|
style.position = "relative";
|
|
406
436
|
} else {
|
|
@@ -427,10 +457,11 @@ function useFixedStyle({ props, tableHeaderLast, virtualScroll, virtualScrollX,
|
|
|
427
457
|
style.right = `${virtualX_offsetRight.value}px`;
|
|
428
458
|
}
|
|
429
459
|
} else {
|
|
460
|
+
const lr = (col.dataIndex ? colKeyStore[col.dataIndex] : refStore.get(col)) + "px";
|
|
430
461
|
if (isFixedLeft) {
|
|
431
|
-
style.left =
|
|
462
|
+
style.left = lr;
|
|
432
463
|
} else {
|
|
433
|
-
style.right =
|
|
464
|
+
style.right = lr;
|
|
434
465
|
}
|
|
435
466
|
}
|
|
436
467
|
}
|
|
@@ -444,9 +475,9 @@ const HIGHLIGHT_ROW_CLASS = "highlight-row";
|
|
|
444
475
|
const HIGHLIGHT_CELL_CLASS = "highlight-cell";
|
|
445
476
|
function useHighlight({ props, tableContainer }) {
|
|
446
477
|
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));
|
|
478
|
+
const highlightFrom = computed(() => Highlight_Color[props.theme].from);
|
|
479
|
+
const highlightTo = computed(() => Highlight_Color[props.theme].to);
|
|
480
|
+
const highlightInter = computed(() => interpolateRgb(highlightFrom.value, highlightTo.value));
|
|
450
481
|
const highlightDimRowKeys = /* @__PURE__ */ new Set();
|
|
451
482
|
const highlightDimRowsTimeout = /* @__PURE__ */ new Map();
|
|
452
483
|
const highlightDimCellsTimeout = /* @__PURE__ */ new Map();
|
|
@@ -569,10 +600,11 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
569
600
|
if (!isMouseOver)
|
|
570
601
|
return;
|
|
571
602
|
e.preventDefault();
|
|
572
|
-
const { scrollTop, rowHeight,
|
|
603
|
+
const { scrollTop, rowHeight, containerHeight } = virtualScroll.value;
|
|
573
604
|
const { scrollLeft } = virtualScrollX.value;
|
|
574
605
|
const { headless, headerRowHeight } = props;
|
|
575
606
|
const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
|
|
607
|
+
const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
|
|
576
608
|
if (e.code === SCROLL_CODES[0]) {
|
|
577
609
|
scrollTo(scrollTop - rowHeight, null);
|
|
578
610
|
} else if (e.code === SCROLL_CODES[1]) {
|
|
@@ -582,9 +614,9 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
582
614
|
} else if (e.code === SCROLL_CODES[3]) {
|
|
583
615
|
scrollTo(null, scrollLeft - rowHeight);
|
|
584
616
|
} else if (e.code === SCROLL_CODES[4]) {
|
|
585
|
-
scrollTo(scrollTop - rowHeight *
|
|
617
|
+
scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
|
|
586
618
|
} else if (e.code === SCROLL_CODES[5]) {
|
|
587
|
-
scrollTo(scrollTop + rowHeight *
|
|
619
|
+
scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
|
|
588
620
|
}
|
|
589
621
|
}
|
|
590
622
|
function handleMouseEnter() {
|
|
@@ -650,7 +682,13 @@ function useThDrag({ props, emits }) {
|
|
|
650
682
|
};
|
|
651
683
|
}
|
|
652
684
|
const VUE2_SCROLL_TIMEOUT_MS = 200;
|
|
653
|
-
function useVirtualScroll({
|
|
685
|
+
function useVirtualScroll({
|
|
686
|
+
props,
|
|
687
|
+
tableContainer,
|
|
688
|
+
dataSourceCopy,
|
|
689
|
+
tableHeaderLast,
|
|
690
|
+
tableHeaders
|
|
691
|
+
}) {
|
|
654
692
|
const virtualScroll = ref({
|
|
655
693
|
containerHeight: 0,
|
|
656
694
|
rowHeight: props.rowHeight,
|
|
@@ -728,11 +766,13 @@ function useVirtualScroll({ props, tableContainer, dataSourceCopy, tableHeaderLa
|
|
|
728
766
|
} else {
|
|
729
767
|
containerHeight = offsetHeight || Default_Table_Height;
|
|
730
768
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
769
|
+
const { headless, headerRowHeight } = props;
|
|
770
|
+
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
771
|
+
if (!headless) {
|
|
772
|
+
const headerToBodyRowHeightCount = Math.floor(tableHeaders.value.length * (headerRowHeight || rowHeight) / rowHeight);
|
|
773
|
+
pageSize -= headerToBodyRowHeightCount;
|
|
774
|
+
}
|
|
775
|
+
Object.assign(virtualScroll.value, { containerHeight, pageSize });
|
|
736
776
|
updateVirtualScrollY(scrollTop);
|
|
737
777
|
}
|
|
738
778
|
function initVirtualScrollX() {
|
|
@@ -749,9 +789,27 @@ function useVirtualScroll({ props, tableContainer, dataSourceCopy, tableHeaderLa
|
|
|
749
789
|
let vue2ScrollYTimeout = null;
|
|
750
790
|
function updateVirtualScrollY(sTop = 0) {
|
|
751
791
|
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex } = virtualScroll.value;
|
|
752
|
-
|
|
753
|
-
|
|
792
|
+
virtualScroll.value.scrollTop = sTop;
|
|
793
|
+
let startIndex = Math.floor(sTop / rowHeight);
|
|
794
|
+
if (props.stripe) {
|
|
795
|
+
startIndex -= 1;
|
|
796
|
+
}
|
|
797
|
+
if (startIndex < 0) {
|
|
798
|
+
startIndex = 0;
|
|
799
|
+
}
|
|
800
|
+
if (props.stripe && startIndex !== 0) {
|
|
801
|
+
const scrollRows = Math.abs(oldStartIndex - startIndex);
|
|
802
|
+
if (scrollRows < 2) {
|
|
803
|
+
return;
|
|
804
|
+
} else if (scrollRows % 2) {
|
|
805
|
+
startIndex -= 1;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
754
808
|
let endIndex = startIndex + pageSize;
|
|
809
|
+
if (props.stripe) {
|
|
810
|
+
endIndex += 2;
|
|
811
|
+
}
|
|
812
|
+
const offsetTop = startIndex * rowHeight;
|
|
755
813
|
if (endIndex > dataSourceCopy.value.length) {
|
|
756
814
|
endIndex = dataSourceCopy.value.length;
|
|
757
815
|
}
|
|
@@ -761,12 +819,11 @@ function useVirtualScroll({ props, tableContainer, dataSourceCopy, tableHeaderLa
|
|
|
761
819
|
if (!props.optimizeVue2Scroll || sTop <= scrollTop || Math.abs(oldStartIndex - startIndex) >= pageSize) {
|
|
762
820
|
Object.assign(virtualScroll.value, {
|
|
763
821
|
startIndex,
|
|
764
|
-
offsetTop,
|
|
765
822
|
endIndex,
|
|
766
|
-
|
|
823
|
+
offsetTop
|
|
767
824
|
});
|
|
768
825
|
} else {
|
|
769
|
-
|
|
826
|
+
virtualScroll.value.endIndex = endIndex;
|
|
770
827
|
vue2ScrollYTimeout = window.setTimeout(() => {
|
|
771
828
|
Object.assign(virtualScroll.value, { startIndex, offsetTop });
|
|
772
829
|
}, VUE2_SCROLL_TIMEOUT_MS);
|
|
@@ -913,8 +970,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
913
970
|
fixedColShadow: { type: Boolean, default: false },
|
|
914
971
|
optimizeVue2Scroll: { type: Boolean, default: false },
|
|
915
972
|
sortConfig: { default: () => ({
|
|
916
|
-
emptyToBottom: false
|
|
917
|
-
|
|
973
|
+
emptyToBottom: false,
|
|
974
|
+
stringLocaleCompare: true
|
|
975
|
+
}) },
|
|
976
|
+
hideHeaderTitle: { type: [Boolean, Array], default: false }
|
|
918
977
|
},
|
|
919
978
|
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"],
|
|
920
979
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
@@ -955,10 +1014,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
955
1014
|
initVirtualScrollX,
|
|
956
1015
|
updateVirtualScrollY,
|
|
957
1016
|
updateVirtualScrollX
|
|
958
|
-
} = useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLast });
|
|
1017
|
+
} = useVirtualScroll({ tableContainer, props, dataSourceCopy, tableHeaderLast, tableHeaders });
|
|
959
1018
|
const { getFixedStyle } = useFixedStyle({
|
|
960
1019
|
props,
|
|
961
|
-
|
|
1020
|
+
tableHeaders,
|
|
962
1021
|
virtualScroll,
|
|
963
1022
|
virtualScrollX,
|
|
964
1023
|
virtualX_on,
|
|
@@ -1038,17 +1097,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1038
1097
|
tableHeaders.value[depth] = [];
|
|
1039
1098
|
}
|
|
1040
1099
|
let allChildrenLen = 0;
|
|
1100
|
+
let allChildrenWidthSum = 0;
|
|
1041
1101
|
arr.forEach((col) => {
|
|
1042
1102
|
col.__PARENT__ = parent;
|
|
1043
1103
|
let colChildrenLen = 1;
|
|
1104
|
+
let colWidth = 0;
|
|
1044
1105
|
if (col.children) {
|
|
1045
|
-
|
|
1106
|
+
const [len, widthSum] = flat(
|
|
1046
1107
|
col.children,
|
|
1047
1108
|
col,
|
|
1048
1109
|
depth + 1
|
|
1049
1110
|
/* , col.fixed */
|
|
1050
1111
|
);
|
|
1112
|
+
colChildrenLen = len;
|
|
1113
|
+
colWidth = widthSum;
|
|
1051
1114
|
} else {
|
|
1115
|
+
colWidth = getColWidth(col);
|
|
1052
1116
|
tempHeaderLast.push(col);
|
|
1053
1117
|
}
|
|
1054
1118
|
tableHeaders.value[depth].push(col);
|
|
@@ -1060,9 +1124,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1060
1124
|
if (colSpan !== 1) {
|
|
1061
1125
|
col.colSpan = colSpan;
|
|
1062
1126
|
}
|
|
1127
|
+
if (!props.fixedMode && col.width === void 0) {
|
|
1128
|
+
col.width = colWidth + "px";
|
|
1129
|
+
}
|
|
1063
1130
|
allChildrenLen += colChildrenLen;
|
|
1131
|
+
allChildrenWidthSum += colWidth;
|
|
1064
1132
|
});
|
|
1065
|
-
return allChildrenLen;
|
|
1133
|
+
return [allChildrenLen, allChildrenWidthSum];
|
|
1066
1134
|
}
|
|
1067
1135
|
flat(copyColumn, null);
|
|
1068
1136
|
tableHeaderLast.value = tempHeaderLast;
|
|
@@ -1082,17 +1150,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1082
1150
|
return typeof props.colKey === "function" ? props.colKey(col) : col[props.colKey];
|
|
1083
1151
|
}
|
|
1084
1152
|
function getColWidthStyle(col) {
|
|
1153
|
+
const width = getColWidthStr(col);
|
|
1154
|
+
const minWidth = getColWidthStr(col, "minWidth");
|
|
1155
|
+
const maxWidth = getColWidthStr(col, "maxWidth");
|
|
1085
1156
|
const style = {
|
|
1086
|
-
width
|
|
1087
|
-
minWidth:
|
|
1088
|
-
maxWidth:
|
|
1157
|
+
width,
|
|
1158
|
+
minWidth: minWidth ?? width,
|
|
1159
|
+
maxWidth: maxWidth ?? width
|
|
1089
1160
|
};
|
|
1090
1161
|
if (props.colResizable) {
|
|
1091
|
-
style.minWidth =
|
|
1092
|
-
style.maxWidth =
|
|
1093
|
-
} else {
|
|
1094
|
-
style.minWidth = col.minWidth === void 0 ? col.width : col.minWidth;
|
|
1095
|
-
style.maxWidth = col.maxWidth === void 0 ? col.width : col.maxWidth;
|
|
1162
|
+
style.minWidth = width;
|
|
1163
|
+
style.maxWidth = width;
|
|
1096
1164
|
}
|
|
1097
1165
|
return style;
|
|
1098
1166
|
}
|
|
@@ -1108,6 +1176,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1108
1176
|
}
|
|
1109
1177
|
return style;
|
|
1110
1178
|
}
|
|
1179
|
+
function getHeaderTitle(col) {
|
|
1180
|
+
if (props.hideHeaderTitle === true || Array.isArray(props.hideHeaderTitle) && props.hideHeaderTitle.includes(col.dataIndex)) {
|
|
1181
|
+
return "";
|
|
1182
|
+
}
|
|
1183
|
+
return col.title || "";
|
|
1184
|
+
}
|
|
1111
1185
|
function onColumnSort(col, click = true, options = {}) {
|
|
1112
1186
|
if (!(col == null ? void 0 : col.sorter))
|
|
1113
1187
|
return;
|
|
@@ -1329,7 +1403,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1329
1403
|
rowspan: unref(virtualX_on) ? 1 : col.rowSpan,
|
|
1330
1404
|
colspan: col.colSpan,
|
|
1331
1405
|
style: normalizeStyle(getCellStyle(1, col, rowIndex)),
|
|
1332
|
-
title: col
|
|
1406
|
+
title: getHeaderTitle(col),
|
|
1333
1407
|
class: normalizeClass([
|
|
1334
1408
|
col.sorter ? "sortable" : "",
|
|
1335
1409
|
col.dataIndex === unref(sortCol) && unref(sortOrderIndex) !== 0 && "sorter-" + sortSwitchOrder[unref(sortOrderIndex)],
|