stk-table-vue 0.8.2 → 0.8.4
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 +21 -54
- package/lib/src/StkTable/StkTable.vue.d.ts +1 -1
- package/lib/src/StkTable/useMaxRowSpan.d.ts +14 -0
- package/lib/src/StkTable/useMergeCells.d.ts +4 -2
- package/lib/src/StkTable/useRowExpand.d.ts +1 -1
- package/lib/src/StkTable/useVirtualScroll.d.ts +3 -2
- package/lib/stk-table-vue.js +151 -81
- package/package.json +1 -1
- package/src/StkTable/StkTable.vue +20 -13
- package/src/StkTable/useMaxRowSpan.ts +56 -0
- package/src/StkTable/useMergeCells.ts +18 -17
- package/src/StkTable/useRowExpand.ts +13 -3
- package/src/StkTable/useVirtualScroll.ts +46 -10
package/README.md
CHANGED
|
@@ -12,57 +12,27 @@
|
|
|
12
12
|
</p>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
|
-
>
|
|
16
|
-
>
|
|
15
|
+
> Stk Table Vue(Sticky Table) is a high-performance virtual list component based on Vue.
|
|
16
|
+
>
|
|
17
|
+
> Used for real-time data display, with data highlighting and dynamic effects
|
|
18
|
+
>
|
|
19
|
+
> Support Vue3 and Vue2.7
|
|
17
20
|
|
|
18
|
-
> Vue2.7支持引入源码(**ts**)使用。
|
|
19
21
|
|
|
20
|
-
##
|
|
21
|
-
|
|
22
|
+
## Documentation
|
|
23
|
+
### [Stk Table Vue Official CN](https://ja-plus.github.io/stk-table-vue/)
|
|
24
|
+
|
|
22
25
|
|
|
23
26
|
## Repo:
|
|
24
27
|
- [Github](https://github.com/ja-plus/stk-table-vue)
|
|
25
28
|
- [Gitee](https://gitee.com/japlus/stk-table-vue) 🇨🇳
|
|
26
29
|
|
|
27
30
|
## Demo
|
|
31
|
+
[<span style="font-size: 16px;font-weight: bold;">Online Demo in stackblitz</span>](https://stackblitz.com/edit/vitejs-vite-ad91hh?file=src%2FDemo%2Findex.vue)
|
|
32
|
+
|
|
33
|
+
## Compare
|
|
34
|
+
Compare performance with other vue table [vue-table-compare](https://github.com/ja-plus/vue-table-compare)
|
|
28
35
|
|
|
29
|
-
[<span style="font-size: 16px;font-weight: bold;">Online Demo</span>](https://stackblitz.com/edit/vitejs-vite-ad91hh?file=src%2FDemo%2Findex.vue)
|
|
30
|
-
|
|
31
|
-
## Feature TODO:
|
|
32
|
-
* [x] 高亮行,单元格。
|
|
33
|
-
- [x] 使用 `Web Animations API` 实现高亮。(`v0.3.4` 变更为默认值)
|
|
34
|
-
- [x] 支持配置高亮参数(持续时间,颜色,频率)。(`v0.2.9`)
|
|
35
|
-
- [x] `setHighlightDimRow`/`setHighlightCellRow`支持自定义高亮css类名。(`v0.2.9`)
|
|
36
|
-
* [x] 虚拟列表。
|
|
37
|
-
- [x] 纵向。
|
|
38
|
-
- [x] 横向(必须设置列宽)。
|
|
39
|
-
- [x] 支持不定行高。(`v0.6.0`)
|
|
40
|
-
* [x] 列固定。
|
|
41
|
-
- [x] 固定列阴影。
|
|
42
|
-
- [x] 多级表头固定列阴影。
|
|
43
|
-
- [x] sticky column 动态计算阴影位置。(`v0.4.0`)
|
|
44
|
-
* [x] 行展开。(`v0.5.0`)
|
|
45
|
-
* [x] 行拖动。(`v0.5.0`)
|
|
46
|
-
* [x] 树形。(`v0.7.0`)
|
|
47
|
-
* [x] 单元格合并。(`v0.8.0`)
|
|
48
|
-
* [] 列筛选。
|
|
49
|
-
* [x] 斑马纹。
|
|
50
|
-
* [x] 拖动更改列顺序。
|
|
51
|
-
* [x] 拖动调整列宽。
|
|
52
|
-
* [x] 排序
|
|
53
|
-
- [x] 支持配置 `null` | `undefined` 永远排最后。
|
|
54
|
-
- [x] 支持配置 string 使用 `String.prototype.localCompare` 排序。
|
|
55
|
-
* [x] 多级表头。
|
|
56
|
-
- [] 横向虚拟滚动。
|
|
57
|
-
* [x] 支持table-layout: fixed 配置。
|
|
58
|
-
* [x] 鼠标悬浮在表格上,键盘滚动虚拟表格。
|
|
59
|
-
- [x] 键盘 `ArrowUp`/`ArrowDown`/`ArrowLeft`/`ArrowRight`/`PageUp`/ `PageDown` 按键支持。
|
|
60
|
-
* [] 非虚拟滚动时,大数据分批加载。
|
|
61
|
-
* [x] vue2.7支持(引入源码使用)。
|
|
62
|
-
- [x] `props.optimizeVue2Scroll` 优化vue2虚拟滚动流畅度。(`v0.2.0`)
|
|
63
|
-
* [x] 支持配置序号列。`StkTableColumn['type']`。(`v0.3.0`)
|
|
64
|
-
* [x] `props.cellHover`单元格悬浮样式。(`v0.3.2`)
|
|
65
|
-
* [] 惯性滚动优化。
|
|
66
36
|
|
|
67
37
|
|
|
68
38
|
## Usage
|
|
@@ -78,17 +48,17 @@ const stkTableRef = useTemplateRef('stkTableRef');
|
|
|
78
48
|
|
|
79
49
|
// highlight row
|
|
80
50
|
stkTableRef.value.setHighlightDimRow([rowKey],{
|
|
81
|
-
method: 'css'|'animation',//
|
|
82
|
-
className: 'custom-class-name', // method css
|
|
51
|
+
method: 'css'|'animation',// default animation。
|
|
52
|
+
className: 'custom-class-name', // method css。
|
|
83
53
|
keyframe: [{backgroundColor:'#aaa'}, {backgroundColor: '#222'}],//same as https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
|
|
84
|
-
duration: 2000
|
|
54
|
+
duration: 2000,。
|
|
85
55
|
});
|
|
86
56
|
// highlight cell
|
|
87
57
|
stkTableRef.value.setHighlightDimCell(rowKey, colDataIndex, {
|
|
88
58
|
method: 'css'|'animation',
|
|
89
|
-
className:'custom-class-name', // method css
|
|
90
|
-
keyframe: [{backgroundColor:'#aaa'}, {backgroundColor: '#222'}], // method animation
|
|
91
|
-
duration: 2000
|
|
59
|
+
className:'custom-class-name', // method css。
|
|
60
|
+
keyframe: [{backgroundColor:'#aaa'}, {backgroundColor: '#222'}], // method animation。
|
|
61
|
+
duration: 2000,。
|
|
92
62
|
});
|
|
93
63
|
|
|
94
64
|
const columns = [
|
|
@@ -114,10 +84,7 @@ const dataSource = [
|
|
|
114
84
|
```
|
|
115
85
|
|
|
116
86
|
### Vue2.7 Usage
|
|
117
|
-
[
|
|
118
|
-
|
|
119
|
-
## Notice
|
|
120
|
-
注意,组件会改动 `props.columns` 中的对象。如果多个组件 `columns` 数组元素存在引用同一个 `StkTableColumn` 对象。则考虑赋值 `columns` 前进行深拷贝。
|
|
87
|
+
[Vue2.7 Usage](https://ja-plus.github.io/stk-table-vue/main/start/vue2-usage.html)
|
|
121
88
|
|
|
122
89
|
## API
|
|
123
90
|
### Props
|
|
@@ -136,7 +103,7 @@ const dataSource = [
|
|
|
136
103
|
[StkTableColumn 列配置](https://ja-plus.github.io/stk-table-vue/main/api/stk-table-column.html)
|
|
137
104
|
|
|
138
105
|
### setHighlightDimCell & setHighlightDimRow
|
|
139
|
-
[
|
|
106
|
+
[Highlight 高亮](https://ja-plus.github.io/stk-table-vue/main/api/expose.html#sethighlightdimcell)
|
|
140
107
|
|
|
141
108
|
|
|
142
109
|
### Example
|
|
@@ -209,4 +176,4 @@ const dataSource = [
|
|
|
209
176
|
|
|
210
177
|
|
|
211
178
|
## Other
|
|
212
|
-
* `$*$`
|
|
179
|
+
* `$*$`
|
|
@@ -347,7 +347,7 @@ declare const __VLS_component: import('vue').DefineComponent<import('vue').Extra
|
|
|
347
347
|
* en: Set expanded rows
|
|
348
348
|
* @see {@link setRowExpand}
|
|
349
349
|
*/
|
|
350
|
-
setRowExpand: (rowKeyOrRow: string | undefined | PrivateRowDT, expand?: boolean, data?: {
|
|
350
|
+
setRowExpand: (rowKeyOrRow: string | undefined | PrivateRowDT, expand?: boolean | null, data?: {
|
|
351
351
|
col?: StkTableColumn<PrivateRowDT>;
|
|
352
352
|
silent?: boolean;
|
|
353
353
|
}) => void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ShallowRef } from 'vue';
|
|
2
|
+
import { PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
|
|
3
|
+
|
|
4
|
+
type Options = {
|
|
5
|
+
props: any;
|
|
6
|
+
tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
|
|
7
|
+
rowKeyGen: RowKeyGen;
|
|
8
|
+
dataSourceCopy: ShallowRef<any[]>;
|
|
9
|
+
};
|
|
10
|
+
export declare function useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy }: Options): {
|
|
11
|
+
maxRowSpan: Map<UniqKey, number>;
|
|
12
|
+
updateMaxRowSpan: () => void;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ShallowRef } from 'vue';
|
|
2
2
|
import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type Options = {
|
|
5
5
|
props: 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({ props, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart, }: Options): {
|
|
11
12
|
hiddenCellMap: import('vue').Ref<Record<UniqKey, Set<UniqKey>>, Record<UniqKey, Set<UniqKey>>>;
|
|
12
13
|
mergeCellsWrapper: (row: MergeCellsParam<any>["row"], col: MergeCellsParam<any>["col"], rowIndex: MergeCellsParam<any>["rowIndex"], colIndex: MergeCellsParam<any>["colIndex"]) => {
|
|
13
14
|
colspan?: number;
|
|
@@ -18,3 +19,4 @@ export declare function useMergeCells({ props, tableHeaderLast, rowKeyGen, colKe
|
|
|
18
19
|
activeMergedCells: import('vue').Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
|
|
19
20
|
updateActiveMergedCells: (clear?: boolean) => void;
|
|
20
21
|
};
|
|
22
|
+
export {};
|
|
@@ -9,7 +9,7 @@ type Option<DT extends Record<string, any>> = {
|
|
|
9
9
|
};
|
|
10
10
|
export declare function useRowExpand({ dataSourceCopy, rowKeyGen, emits }: Option<DT>): {
|
|
11
11
|
toggleExpandRow: (row: DT, col: StkTableColumn<DT>) => void;
|
|
12
|
-
setRowExpand: (rowKeyOrRow: string | undefined | DT, expand?: boolean, data?: {
|
|
12
|
+
setRowExpand: (rowKeyOrRow: string | undefined | DT, expand?: boolean | null, data?: {
|
|
13
13
|
col?: StkTableColumn<DT>;
|
|
14
14
|
silent?: boolean;
|
|
15
15
|
}) => void;
|
|
@@ -9,6 +9,7 @@ type Option<DT extends Record<string, any>> = {
|
|
|
9
9
|
tableHeaderLast: ShallowRef<PrivateStkTableColumn<DT>[]>;
|
|
10
10
|
tableHeaders: ShallowRef<PrivateStkTableColumn<DT>[][]>;
|
|
11
11
|
rowKeyGen: RowKeyGen;
|
|
12
|
+
maxRowSpan: Map<UniqKey, number>;
|
|
12
13
|
};
|
|
13
14
|
/** 暂存纵向虚拟滚动的数据 */
|
|
14
15
|
export type VirtualScrollStore = {
|
|
@@ -45,11 +46,11 @@ export type VirtualScrollXStore = {
|
|
|
45
46
|
scrollLeft: number;
|
|
46
47
|
};
|
|
47
48
|
/**
|
|
48
|
-
*
|
|
49
|
+
* virtual scroll
|
|
49
50
|
* @param param0
|
|
50
51
|
* @returns
|
|
51
52
|
*/
|
|
52
|
-
export declare function useVirtualScroll<DT extends Record<string, any>>({ props, tableContainerRef, trRef, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen, }: Option<DT>): {
|
|
53
|
+
export declare function useVirtualScroll<DT extends Record<string, any>>({ props, tableContainerRef, trRef, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen, maxRowSpan, }: Option<DT>): {
|
|
53
54
|
virtualScroll: Ref<{
|
|
54
55
|
containerHeight: number;
|
|
55
56
|
pageSize: number;
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -853,9 +853,114 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
853
853
|
if (!isMouseOver) isMouseOver = true;
|
|
854
854
|
}
|
|
855
855
|
}
|
|
856
|
+
function useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy }) {
|
|
857
|
+
const maxRowSpan = /* @__PURE__ */ new Map();
|
|
858
|
+
function updateMaxRowSpan() {
|
|
859
|
+
if (!props.virtual) {
|
|
860
|
+
if (maxRowSpan.size) maxRowSpan.clear();
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
maxRowSpan.clear();
|
|
864
|
+
const data = dataSourceCopy.value;
|
|
865
|
+
const columns = tableHeaderLast.value;
|
|
866
|
+
const columnsWithMerge = columns.filter((col) => col.mergeCells);
|
|
867
|
+
if (!columnsWithMerge.length) return;
|
|
868
|
+
const dataLength = data.length;
|
|
869
|
+
const mergeColumnsLength = columnsWithMerge.length;
|
|
870
|
+
for (let rowIndex = 0; rowIndex < dataLength; rowIndex++) {
|
|
871
|
+
const row = data[rowIndex];
|
|
872
|
+
const rowKey = rowKeyGen(row);
|
|
873
|
+
let currentMax = maxRowSpan.get(rowKey) || 0;
|
|
874
|
+
for (let colIndex = 0; colIndex < mergeColumnsLength; colIndex++) {
|
|
875
|
+
const col = columnsWithMerge[colIndex];
|
|
876
|
+
const { rowspan = 1 } = col.mergeCells({ row, col, rowIndex, colIndex }) || {};
|
|
877
|
+
if (rowspan > 1 && rowspan > currentMax) {
|
|
878
|
+
currentMax = rowspan;
|
|
879
|
+
maxRowSpan.set(rowKey, currentMax);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
return {
|
|
885
|
+
maxRowSpan,
|
|
886
|
+
updateMaxRowSpan
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
function useMergeCells({
|
|
890
|
+
props,
|
|
891
|
+
tableHeaderLast,
|
|
892
|
+
rowKeyGen,
|
|
893
|
+
colKeyGen,
|
|
894
|
+
virtual_dataSourcePart
|
|
895
|
+
}) {
|
|
896
|
+
const hiddenCellMap = ref({});
|
|
897
|
+
const hoverRowMap = ref({});
|
|
898
|
+
const hoverMergedCells = ref(/* @__PURE__ */ new Set());
|
|
899
|
+
const activeMergedCells = ref(/* @__PURE__ */ new Set());
|
|
900
|
+
watch([virtual_dataSourcePart, tableHeaderLast], () => {
|
|
901
|
+
hiddenCellMap.value = {};
|
|
902
|
+
hoverRowMap.value = {};
|
|
903
|
+
});
|
|
904
|
+
function hideCells(rowKey, startIndex, count, isSelfRow = false, mergeCellKey) {
|
|
905
|
+
for (let i = startIndex; i < startIndex + count; i++) {
|
|
906
|
+
if (!isSelfRow || i !== startIndex) {
|
|
907
|
+
const nextCol = tableHeaderLast.value[i];
|
|
908
|
+
if (!nextCol) break;
|
|
909
|
+
const nextColKey = colKeyGen.value(nextCol);
|
|
910
|
+
if (!hiddenCellMap.value[rowKey]) hiddenCellMap.value[rowKey] = /* @__PURE__ */ new Set();
|
|
911
|
+
hiddenCellMap.value[rowKey].add(nextColKey);
|
|
912
|
+
}
|
|
913
|
+
if (!hoverRowMap.value[rowKey]) hoverRowMap.value[rowKey] = /* @__PURE__ */ new Set();
|
|
914
|
+
hoverRowMap.value[rowKey].add(mergeCellKey);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
function mergeCellsWrapper(row, col, rowIndex, colIndex) {
|
|
918
|
+
if (!col.mergeCells) return;
|
|
919
|
+
let { colspan, rowspan } = col.mergeCells({ row, col, rowIndex, colIndex }) || {};
|
|
920
|
+
colspan = colspan || 1;
|
|
921
|
+
rowspan = rowspan || 1;
|
|
922
|
+
if (colspan === 1 && rowspan === 1) return;
|
|
923
|
+
const rowKey = rowKeyGen(row);
|
|
924
|
+
const colKey = colKeyGen.value(col);
|
|
925
|
+
const curColIndex = tableHeaderLast.value.findIndex((item) => colKeyGen.value(item) === colKey);
|
|
926
|
+
const curRowIndex = virtual_dataSourcePart.value.findIndex((item) => rowKeyGen(item) === rowKey);
|
|
927
|
+
const mergedCellKey = pureCellKeyGen(rowKey, colKey);
|
|
928
|
+
if (curRowIndex === -1) return;
|
|
929
|
+
for (let i = curRowIndex; i < curRowIndex + rowspan; i++) {
|
|
930
|
+
const row2 = virtual_dataSourcePart.value[i];
|
|
931
|
+
if (!row2) break;
|
|
932
|
+
hideCells(rowKeyGen(row2), curColIndex, colspan, i === curRowIndex, mergedCellKey);
|
|
933
|
+
}
|
|
934
|
+
return { colspan, rowspan };
|
|
935
|
+
}
|
|
936
|
+
function updateHoverMergedCells(rowKey) {
|
|
937
|
+
const set = rowKey === void 0 ? null : hoverRowMap.value[rowKey];
|
|
938
|
+
hoverMergedCells.value = set || /* @__PURE__ */ new Set();
|
|
939
|
+
}
|
|
940
|
+
function updateActiveMergedCells(clear) {
|
|
941
|
+
if (!props.rowActive) return;
|
|
942
|
+
if (clear) {
|
|
943
|
+
activeMergedCells.value.clear();
|
|
944
|
+
} else {
|
|
945
|
+
activeMergedCells.value = new Set(hoverMergedCells.value);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return {
|
|
949
|
+
hiddenCellMap,
|
|
950
|
+
mergeCellsWrapper,
|
|
951
|
+
hoverMergedCells,
|
|
952
|
+
updateHoverMergedCells,
|
|
953
|
+
activeMergedCells,
|
|
954
|
+
updateActiveMergedCells
|
|
955
|
+
};
|
|
956
|
+
}
|
|
856
957
|
function useRowExpand({ dataSourceCopy, rowKeyGen, emits }) {
|
|
958
|
+
const expandedKey = "__EXPANDED__";
|
|
959
|
+
function isExpanded(row, col) {
|
|
960
|
+
return (row == null ? void 0 : row[expandedKey]) === col ? !(row == null ? void 0 : row[expandedKey]) : true;
|
|
961
|
+
}
|
|
857
962
|
function toggleExpandRow(row, col) {
|
|
858
|
-
const isExpand = (row
|
|
963
|
+
const isExpand = isExpanded(row, col);
|
|
859
964
|
setRowExpand(row, isExpand, { col });
|
|
860
965
|
}
|
|
861
966
|
function setRowExpand(rowKeyOrRow, expand, data) {
|
|
@@ -883,6 +988,9 @@ function useRowExpand({ dataSourceCopy, rowKeyGen, emits }) {
|
|
|
883
988
|
}
|
|
884
989
|
const row = tempData[index];
|
|
885
990
|
const col = (data == null ? void 0 : data.col) || null;
|
|
991
|
+
if (expand == null) {
|
|
992
|
+
expand = isExpanded(row, col);
|
|
993
|
+
}
|
|
886
994
|
if (expand) {
|
|
887
995
|
const newExpandRow = {
|
|
888
996
|
__ROW_KEY__: EXPANDED_ROW_KEY_PREFIX + rowKey,
|
|
@@ -1253,7 +1361,8 @@ function useVirtualScroll({
|
|
|
1253
1361
|
dataSourceCopy,
|
|
1254
1362
|
tableHeaderLast,
|
|
1255
1363
|
tableHeaders,
|
|
1256
|
-
rowKeyGen
|
|
1364
|
+
rowKeyGen,
|
|
1365
|
+
maxRowSpan
|
|
1257
1366
|
}) {
|
|
1258
1367
|
const tableHeaderHeight = ref(props.headerRowHeight);
|
|
1259
1368
|
const virtualScroll = ref({
|
|
@@ -1458,6 +1567,32 @@ function useVirtualScroll({
|
|
|
1458
1567
|
startIndex = Math.floor(sTop / rowHeight);
|
|
1459
1568
|
endIndex = startIndex + pageSize;
|
|
1460
1569
|
}
|
|
1570
|
+
if (maxRowSpan.size) {
|
|
1571
|
+
let correctedStartIndex = startIndex;
|
|
1572
|
+
let correctedEndIndex = endIndex;
|
|
1573
|
+
for (let i = 0; i < startIndex; i++) {
|
|
1574
|
+
const row = dataSourceCopyTemp[i];
|
|
1575
|
+
if (!row) continue;
|
|
1576
|
+
const spanEndIndex = i + (maxRowSpan.get(rowKeyGen(row)) || 1);
|
|
1577
|
+
if (spanEndIndex > startIndex) {
|
|
1578
|
+
correctedStartIndex = i;
|
|
1579
|
+
if (spanEndIndex > endIndex) {
|
|
1580
|
+
correctedEndIndex = spanEndIndex;
|
|
1581
|
+
}
|
|
1582
|
+
break;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
for (let i = correctedStartIndex; i < endIndex; i++) {
|
|
1586
|
+
const row = dataSourceCopyTemp[i];
|
|
1587
|
+
if (!row) continue;
|
|
1588
|
+
const spanEndIndex = i + (maxRowSpan.get(rowKeyGen(row)) || 1);
|
|
1589
|
+
if (spanEndIndex > correctedEndIndex) {
|
|
1590
|
+
correctedEndIndex = Math.max(spanEndIndex, correctedEndIndex);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
startIndex = correctedStartIndex;
|
|
1594
|
+
endIndex = correctedEndIndex;
|
|
1595
|
+
}
|
|
1461
1596
|
if (stripe && startIndex > 0 && startIndex % 2) {
|
|
1462
1597
|
startIndex -= 1;
|
|
1463
1598
|
if (autoRowHeight || hasExpandCol.value) {
|
|
@@ -1561,77 +1696,6 @@ function useVirtualScroll({
|
|
|
1561
1696
|
clearAllAutoHeight
|
|
1562
1697
|
};
|
|
1563
1698
|
}
|
|
1564
|
-
function useMergeCells({
|
|
1565
|
-
props,
|
|
1566
|
-
tableHeaderLast,
|
|
1567
|
-
rowKeyGen,
|
|
1568
|
-
colKeyGen,
|
|
1569
|
-
virtual_dataSourcePart
|
|
1570
|
-
}) {
|
|
1571
|
-
const hiddenCellMap = ref({});
|
|
1572
|
-
const hoverRowMap = ref({});
|
|
1573
|
-
const hoverMergedCells = ref(/* @__PURE__ */ new Set());
|
|
1574
|
-
const activeMergedCells = ref(/* @__PURE__ */ new Set());
|
|
1575
|
-
watch([virtual_dataSourcePart, tableHeaderLast], () => {
|
|
1576
|
-
hiddenCellMap.value = {};
|
|
1577
|
-
hoverRowMap.value = {};
|
|
1578
|
-
});
|
|
1579
|
-
function hideCells(rowKey, startIndex, count, isSelfRow = false, mergeCellKey) {
|
|
1580
|
-
for (let i = startIndex; i < startIndex + count; i++) {
|
|
1581
|
-
if (!isSelfRow || i !== startIndex) {
|
|
1582
|
-
const nextCol = tableHeaderLast.value[i];
|
|
1583
|
-
if (!nextCol) break;
|
|
1584
|
-
const nextColKey = colKeyGen.value(nextCol);
|
|
1585
|
-
if (!hiddenCellMap.value[rowKey]) hiddenCellMap.value[rowKey] = /* @__PURE__ */ new Set();
|
|
1586
|
-
hiddenCellMap.value[rowKey].add(nextColKey);
|
|
1587
|
-
}
|
|
1588
|
-
if (!hoverRowMap.value[rowKey]) hoverRowMap.value[rowKey] = /* @__PURE__ */ new Set();
|
|
1589
|
-
hoverRowMap.value[rowKey].add(mergeCellKey);
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
function mergeCellsWrapper(row, col, rowIndex, colIndex) {
|
|
1593
|
-
if (!col.mergeCells) return;
|
|
1594
|
-
let { colspan, rowspan } = col.mergeCells({ row, col, rowIndex, colIndex }) || {};
|
|
1595
|
-
colspan = colspan || 1;
|
|
1596
|
-
rowspan = rowspan || 1;
|
|
1597
|
-
if (colspan === 1 && rowspan === 1) return;
|
|
1598
|
-
const rowKey = rowKeyGen(row);
|
|
1599
|
-
const colKey = colKeyGen.value(col);
|
|
1600
|
-
const dataSourceSlice = virtual_dataSourcePart.value.slice();
|
|
1601
|
-
const curColIndex = tableHeaderLast.value.findIndex((item) => colKeyGen.value(item) === colKey);
|
|
1602
|
-
const curRowIndex = dataSourceSlice.findIndex((item) => rowKeyGen(item) === rowKey);
|
|
1603
|
-
const mergedCellKey = pureCellKeyGen(rowKey, colKey);
|
|
1604
|
-
if (curRowIndex === -1) return;
|
|
1605
|
-
for (let i = curRowIndex; i < curRowIndex + rowspan; i++) {
|
|
1606
|
-
const row2 = dataSourceSlice[i];
|
|
1607
|
-
if (!row2) break;
|
|
1608
|
-
const rKey = rowKeyGen(row2);
|
|
1609
|
-
const isSelfRow = i === curRowIndex;
|
|
1610
|
-
hideCells(rKey, curColIndex, colspan, isSelfRow, mergedCellKey);
|
|
1611
|
-
}
|
|
1612
|
-
return { colspan, rowspan };
|
|
1613
|
-
}
|
|
1614
|
-
function updateHoverMergedCells(rowKey) {
|
|
1615
|
-
const set = rowKey === void 0 ? null : hoverRowMap.value[rowKey];
|
|
1616
|
-
hoverMergedCells.value = set || /* @__PURE__ */ new Set();
|
|
1617
|
-
}
|
|
1618
|
-
function updateActiveMergedCells(clear) {
|
|
1619
|
-
if (!props.rowActive) return;
|
|
1620
|
-
if (clear) {
|
|
1621
|
-
activeMergedCells.value.clear();
|
|
1622
|
-
} else {
|
|
1623
|
-
activeMergedCells.value = new Set(hoverMergedCells.value);
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1626
|
-
return {
|
|
1627
|
-
hiddenCellMap,
|
|
1628
|
-
mergeCellsWrapper,
|
|
1629
|
-
hoverMergedCells,
|
|
1630
|
-
updateHoverMergedCells,
|
|
1631
|
-
activeMergedCells,
|
|
1632
|
-
updateActiveMergedCells
|
|
1633
|
-
};
|
|
1634
|
-
}
|
|
1635
1699
|
const _hoisted_1 = ["data-col-key", "draggable", "rowspan", "colspan", "title", "onClick"];
|
|
1636
1700
|
const _hoisted_2 = ["onMousedown"];
|
|
1637
1701
|
const _hoisted_3 = { class: "table-header-title" };
|
|
@@ -1759,6 +1823,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1759
1823
|
const { isSRBRActive } = useScrollRowByRow({ props, tableContainerRef });
|
|
1760
1824
|
const { onThDragStart, onThDragOver, onThDrop, isHeaderDraggable } = useThDrag({ props, emits, colKeyGen });
|
|
1761
1825
|
const { onTrDragStart, onTrDrop, onTrDragOver, onTrDragEnd, onTrDragEnter } = useTrDrag({ props, emits, dataSourceCopy });
|
|
1826
|
+
const { maxRowSpan, updateMaxRowSpan } = useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy });
|
|
1762
1827
|
const {
|
|
1763
1828
|
virtualScroll,
|
|
1764
1829
|
virtualScrollX,
|
|
@@ -1775,7 +1840,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1775
1840
|
updateVirtualScrollX,
|
|
1776
1841
|
setAutoHeight,
|
|
1777
1842
|
clearAllAutoHeight
|
|
1778
|
-
} = useVirtualScroll({ tableContainerRef, trRef, props, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen });
|
|
1843
|
+
} = useVirtualScroll({ tableContainerRef, trRef, props, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen, maxRowSpan });
|
|
1844
|
+
const {
|
|
1845
|
+
hiddenCellMap,
|
|
1846
|
+
//
|
|
1847
|
+
mergeCellsWrapper,
|
|
1848
|
+
hoverMergedCells,
|
|
1849
|
+
updateHoverMergedCells,
|
|
1850
|
+
activeMergedCells,
|
|
1851
|
+
updateActiveMergedCells
|
|
1852
|
+
} = useMergeCells({ props, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
|
|
1779
1853
|
const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeadersForCalc });
|
|
1780
1854
|
const getFixedStyle = useFixedStyle({
|
|
1781
1855
|
props,
|
|
@@ -1817,17 +1891,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1817
1891
|
});
|
|
1818
1892
|
const { toggleExpandRow, setRowExpand } = useRowExpand({ dataSourceCopy, rowKeyGen, emits });
|
|
1819
1893
|
const { toggleTreeNode, setTreeExpand, flatTreeData } = useTree({ props, dataSourceCopy, rowKeyGen, emits });
|
|
1820
|
-
const { hiddenCellMap, mergeCellsWrapper, hoverMergedCells, updateHoverMergedCells, activeMergedCells, updateActiveMergedCells } = useMergeCells({
|
|
1821
|
-
props,
|
|
1822
|
-
tableHeaderLast,
|
|
1823
|
-
rowKeyGen,
|
|
1824
|
-
colKeyGen,
|
|
1825
|
-
virtual_dataSourcePart
|
|
1826
|
-
});
|
|
1827
1894
|
watch(
|
|
1828
1895
|
() => props.columns,
|
|
1829
1896
|
() => {
|
|
1830
1897
|
dealColumns();
|
|
1898
|
+
updateMaxRowSpan();
|
|
1831
1899
|
nextTick(() => {
|
|
1832
1900
|
initVirtualScrollX();
|
|
1833
1901
|
updateFixedShadow();
|
|
@@ -1870,6 +1938,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1870
1938
|
needInitVirtualScrollY = true;
|
|
1871
1939
|
}
|
|
1872
1940
|
initDataSource(val);
|
|
1941
|
+
updateMaxRowSpan();
|
|
1873
1942
|
if (needInitVirtualScrollY) {
|
|
1874
1943
|
nextTick(() => initVirtualScrollY());
|
|
1875
1944
|
}
|
|
@@ -1887,6 +1956,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1887
1956
|
);
|
|
1888
1957
|
dealColumns();
|
|
1889
1958
|
initDataSource();
|
|
1959
|
+
updateMaxRowSpan();
|
|
1890
1960
|
onMounted(() => {
|
|
1891
1961
|
initVirtualScroll();
|
|
1892
1962
|
updateFixedShadow();
|
package/package.json
CHANGED
|
@@ -293,13 +293,14 @@ import { useFixedStyle } from './useFixedStyle';
|
|
|
293
293
|
import { useGetFixedColPosition } from './useGetFixedColPosition';
|
|
294
294
|
import { useHighlight } from './useHighlight';
|
|
295
295
|
import { useKeyboardArrowScroll } from './useKeyboardArrowScroll';
|
|
296
|
+
import { useMaxRowSpan } from './useMaxRowSpan';
|
|
297
|
+
import { useMergeCells } from './useMergeCells';
|
|
296
298
|
import { useRowExpand } from './useRowExpand';
|
|
297
299
|
import { useScrollRowByRow } from './useScrollRowByRow';
|
|
298
300
|
import { useThDrag } from './useThDrag';
|
|
299
301
|
import { useTrDrag } from './useTrDrag';
|
|
300
302
|
import { useTree } from './useTree';
|
|
301
303
|
import { useVirtualScroll } from './useVirtualScroll';
|
|
302
|
-
import { useMergeCells } from './useMergeCells';
|
|
303
304
|
import { createStkTableId, getCalculatedColWidth, getColWidth } from './utils/constRefUtils';
|
|
304
305
|
import { howDeepTheHeader, isEmptyValue, tableSort, transformWidthToStr } from './utils/index';
|
|
305
306
|
|
|
@@ -687,7 +688,7 @@ const sortSwitchOrder: Order[] = [null, 'desc', 'asc'];
|
|
|
687
688
|
* @eg
|
|
688
689
|
* ```js
|
|
689
690
|
* [
|
|
690
|
-
* [{
|
|
691
|
+
* [{dataIndex:'id',...}], // 第0行列配置
|
|
691
692
|
* [], // 第一行列配置
|
|
692
693
|
* //...
|
|
693
694
|
* ]
|
|
@@ -761,6 +762,8 @@ const { onThDragStart, onThDragOver, onThDrop, isHeaderDraggable } = useThDrag({
|
|
|
761
762
|
|
|
762
763
|
const { onTrDragStart, onTrDrop, onTrDragOver, onTrDragEnd, onTrDragEnter } = useTrDrag({ props, emits, dataSourceCopy });
|
|
763
764
|
|
|
765
|
+
const { maxRowSpan, updateMaxRowSpan } = useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy });
|
|
766
|
+
|
|
764
767
|
const {
|
|
765
768
|
virtualScroll,
|
|
766
769
|
virtualScrollX,
|
|
@@ -777,7 +780,16 @@ const {
|
|
|
777
780
|
updateVirtualScrollX,
|
|
778
781
|
setAutoHeight,
|
|
779
782
|
clearAllAutoHeight,
|
|
780
|
-
} = useVirtualScroll({ tableContainerRef, trRef, props, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen });
|
|
783
|
+
} = useVirtualScroll({ tableContainerRef, trRef, props, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen, maxRowSpan });
|
|
784
|
+
|
|
785
|
+
const {
|
|
786
|
+
hiddenCellMap, //
|
|
787
|
+
mergeCellsWrapper,
|
|
788
|
+
hoverMergedCells,
|
|
789
|
+
updateHoverMergedCells,
|
|
790
|
+
activeMergedCells,
|
|
791
|
+
updateActiveMergedCells,
|
|
792
|
+
} = useMergeCells({ props, tableHeaderLast, rowKeyGen, colKeyGen, virtual_dataSourcePart });
|
|
781
793
|
|
|
782
794
|
const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeadersForCalc });
|
|
783
795
|
|
|
@@ -831,19 +843,12 @@ const { toggleExpandRow, setRowExpand } = useRowExpand({ dataSourceCopy, rowKeyG
|
|
|
831
843
|
|
|
832
844
|
const { toggleTreeNode, setTreeExpand, flatTreeData } = useTree({ props, dataSourceCopy, rowKeyGen, emits });
|
|
833
845
|
|
|
834
|
-
const { hiddenCellMap, mergeCellsWrapper, hoverMergedCells, updateHoverMergedCells, activeMergedCells, updateActiveMergedCells } = useMergeCells({
|
|
835
|
-
props,
|
|
836
|
-
tableHeaderLast,
|
|
837
|
-
rowKeyGen,
|
|
838
|
-
colKeyGen,
|
|
839
|
-
virtual_dataSourcePart,
|
|
840
|
-
});
|
|
841
|
-
|
|
842
846
|
watch(
|
|
843
847
|
() => props.columns,
|
|
844
848
|
() => {
|
|
845
849
|
dealColumns();
|
|
846
|
-
|
|
850
|
+
updateMaxRowSpan();
|
|
851
|
+
// nextTick: initVirtualScrollX need get container width。
|
|
847
852
|
nextTick(() => {
|
|
848
853
|
initVirtualScrollX();
|
|
849
854
|
updateFixedShadow();
|
|
@@ -885,12 +890,13 @@ watch(
|
|
|
885
890
|
console.warn('invalid dataSource');
|
|
886
891
|
return;
|
|
887
892
|
}
|
|
888
|
-
|
|
893
|
+
|
|
889
894
|
let needInitVirtualScrollY = false;
|
|
890
895
|
if (dataSourceCopy.value.length !== val.length) {
|
|
891
896
|
needInitVirtualScrollY = true;
|
|
892
897
|
}
|
|
893
898
|
initDataSource(val);
|
|
899
|
+
updateMaxRowSpan();
|
|
894
900
|
// if data length is not change, not init virtual scroll
|
|
895
901
|
if (needInitVirtualScrollY) {
|
|
896
902
|
// wait for table render,initVirtualScrollY has get `dom` operation.
|
|
@@ -913,6 +919,7 @@ watch(
|
|
|
913
919
|
|
|
914
920
|
dealColumns();
|
|
915
921
|
initDataSource();
|
|
922
|
+
updateMaxRowSpan();
|
|
916
923
|
|
|
917
924
|
onMounted(() => {
|
|
918
925
|
initVirtualScroll();
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ShallowRef } from "vue";
|
|
2
|
+
import { PrivateStkTableColumn, RowKeyGen, UniqKey } from "./types";
|
|
3
|
+
|
|
4
|
+
type Options = {
|
|
5
|
+
props:any,
|
|
6
|
+
tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
|
|
7
|
+
rowKeyGen: RowKeyGen;
|
|
8
|
+
dataSourceCopy: ShallowRef<any[]>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useMaxRowSpan({ props, tableHeaderLast, rowKeyGen, dataSourceCopy }: Options) {
|
|
12
|
+
/** max rowspan of each row */
|
|
13
|
+
const maxRowSpan = new Map<UniqKey, number>();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Use dataSourceCopy and tableHeaderLast to calculate maxRowSpan
|
|
17
|
+
* @link {maxRowSpan}
|
|
18
|
+
*/
|
|
19
|
+
function updateMaxRowSpan() {
|
|
20
|
+
if(!props.virtual) {
|
|
21
|
+
if(maxRowSpan.size) maxRowSpan.clear();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
maxRowSpan.clear();
|
|
25
|
+
|
|
26
|
+
const data = dataSourceCopy.value;
|
|
27
|
+
const columns = tableHeaderLast.value;
|
|
28
|
+
|
|
29
|
+
const columnsWithMerge = columns.filter(col => col.mergeCells);
|
|
30
|
+
if (!columnsWithMerge.length) return;
|
|
31
|
+
|
|
32
|
+
const dataLength = data.length;
|
|
33
|
+
const mergeColumnsLength = columnsWithMerge.length;
|
|
34
|
+
|
|
35
|
+
for (let rowIndex = 0; rowIndex < dataLength; rowIndex++) {
|
|
36
|
+
const row = data[rowIndex];
|
|
37
|
+
const rowKey = rowKeyGen(row);
|
|
38
|
+
let currentMax = maxRowSpan.get(rowKey) || 0;
|
|
39
|
+
|
|
40
|
+
for (let colIndex = 0; colIndex < mergeColumnsLength; colIndex++) {
|
|
41
|
+
const col = columnsWithMerge[colIndex];
|
|
42
|
+
const { rowspan = 1 } = col.mergeCells!({ row, col, rowIndex, colIndex }) || {};
|
|
43
|
+
|
|
44
|
+
if (rowspan > 1 && rowspan > currentMax) {
|
|
45
|
+
currentMax = rowspan;
|
|
46
|
+
maxRowSpan.set(rowKey, currentMax);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
maxRowSpan,
|
|
54
|
+
updateMaxRowSpan
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { ref, ShallowRef, watch } from 'vue';
|
|
2
2
|
import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
|
|
3
3
|
import { pureCellKeyGen } from './utils';
|
|
4
|
-
|
|
4
|
+
type Options = {
|
|
5
|
+
props: any;
|
|
6
|
+
tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
|
|
7
|
+
rowKeyGen: RowKeyGen;
|
|
8
|
+
colKeyGen: ColKeyGen;
|
|
9
|
+
virtual_dataSourcePart: ShallowRef<any[]>;
|
|
10
|
+
}
|
|
5
11
|
export function useMergeCells({
|
|
6
12
|
props,
|
|
7
13
|
tableHeaderLast,
|
|
8
14
|
rowKeyGen,
|
|
9
15
|
colKeyGen,
|
|
10
16
|
virtual_dataSourcePart,
|
|
11
|
-
}: {
|
|
12
|
-
props: any;
|
|
13
|
-
tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
|
|
14
|
-
rowKeyGen: RowKeyGen;
|
|
15
|
-
colKeyGen: ColKeyGen;
|
|
16
|
-
virtual_dataSourcePart: ShallowRef<any[]>;
|
|
17
|
-
}) {
|
|
17
|
+
}:Options ) {
|
|
18
18
|
/**
|
|
19
19
|
* which cell need be hidden
|
|
20
20
|
* - key: rowKey
|
|
@@ -33,16 +33,19 @@ export function useMergeCells({
|
|
|
33
33
|
/** click current row , which rowspan cells should be highlight */
|
|
34
34
|
const activeMergedCells = ref(new Set<string>());
|
|
35
35
|
|
|
36
|
+
|
|
36
37
|
watch([virtual_dataSourcePart, tableHeaderLast], () => {
|
|
37
38
|
hiddenCellMap.value = {};
|
|
38
39
|
hoverRowMap.value = {};
|
|
39
40
|
});
|
|
40
41
|
|
|
41
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* abstract the logic of hiding cells
|
|
44
|
+
*/
|
|
42
45
|
function hideCells(rowKey: UniqKey, startIndex: number, count: number, isSelfRow = false, mergeCellKey: string) {
|
|
43
46
|
for (let i = startIndex; i < startIndex + count; i++) {
|
|
44
47
|
if (!isSelfRow || i !== startIndex) {
|
|
45
|
-
//
|
|
48
|
+
// self row does not need to be hidden
|
|
46
49
|
const nextCol = tableHeaderLast.value[i];
|
|
47
50
|
if (!nextCol) break;
|
|
48
51
|
const nextColKey = colKeyGen.value(nextCol);
|
|
@@ -81,20 +84,18 @@ export function useMergeCells({
|
|
|
81
84
|
if (colspan === 1 && rowspan === 1) return;
|
|
82
85
|
|
|
83
86
|
const rowKey = rowKeyGen(row);
|
|
87
|
+
|
|
84
88
|
const colKey = colKeyGen.value(col);
|
|
85
|
-
const dataSourceSlice = virtual_dataSourcePart.value.slice();
|
|
86
89
|
const curColIndex = tableHeaderLast.value.findIndex(item => colKeyGen.value(item) === colKey);
|
|
87
|
-
const curRowIndex =
|
|
90
|
+
const curRowIndex = virtual_dataSourcePart.value.findIndex(item => rowKeyGen(item) === rowKey);
|
|
88
91
|
const mergedCellKey = pureCellKeyGen(rowKey, colKey);
|
|
89
92
|
|
|
90
93
|
if (curRowIndex === -1) return;
|
|
91
|
-
|
|
94
|
+
|
|
92
95
|
for (let i = curRowIndex; i < curRowIndex + rowspan; i++) {
|
|
93
|
-
const row =
|
|
96
|
+
const row = virtual_dataSourcePart.value[i];
|
|
94
97
|
if (!row) break;
|
|
95
|
-
|
|
96
|
-
const isSelfRow = i === curRowIndex;
|
|
97
|
-
hideCells(rKey, curColIndex, colspan, isSelfRow, mergedCellKey);
|
|
98
|
+
hideCells(rowKeyGen(row), curColIndex, colspan, i === curRowIndex, mergedCellKey);
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
return { colspan, rowspan };
|
|
@@ -9,26 +9,32 @@ type Option<DT extends Record<string, any>> = {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export function useRowExpand({ dataSourceCopy, rowKeyGen, emits }: Option<DT>) {
|
|
12
|
+
const expandedKey = '__EXPANDED__';
|
|
13
|
+
|
|
14
|
+
function isExpanded(row: DT, col?: StkTableColumn<DT> | null) {
|
|
15
|
+
return row?.[expandedKey] === col ? !row?.[expandedKey] : true;
|
|
16
|
+
}
|
|
12
17
|
/** click expended icon to toggle expand row */
|
|
13
18
|
function toggleExpandRow(row: DT, col: StkTableColumn<DT>) {
|
|
14
|
-
const isExpand = row
|
|
19
|
+
const isExpand = isExpanded(row, col);
|
|
15
20
|
setRowExpand(row, isExpand, { col });
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
/**
|
|
19
24
|
*
|
|
20
25
|
* @param rowKeyOrRow rowKey or row
|
|
21
|
-
* @param expand expand or collapse
|
|
26
|
+
* @param expand expand or collapse, if set null, toggle expand
|
|
22
27
|
* @param data { col?: StkTableColumn<DT> }
|
|
23
28
|
* @param data.silent if set true, not emit `toggle-row-expand`, default:false
|
|
24
29
|
*/
|
|
25
|
-
function setRowExpand(rowKeyOrRow: string | undefined | DT, expand?: boolean, data?: { col?: StkTableColumn<DT>; silent?: boolean }) {
|
|
30
|
+
function setRowExpand(rowKeyOrRow: string | undefined | DT, expand?: boolean | null, data?: { col?: StkTableColumn<DT>; silent?: boolean }) {
|
|
26
31
|
let rowKey: UniqKey;
|
|
27
32
|
if (typeof rowKeyOrRow === 'string') {
|
|
28
33
|
rowKey = rowKeyOrRow;
|
|
29
34
|
} else {
|
|
30
35
|
rowKey = rowKeyGen(rowKeyOrRow);
|
|
31
36
|
}
|
|
37
|
+
|
|
32
38
|
const tempData = dataSourceCopy.value.slice();
|
|
33
39
|
const index = tempData.findIndex(it => rowKeyGen(it) === rowKey);
|
|
34
40
|
if (index === -1) {
|
|
@@ -51,6 +57,10 @@ export function useRowExpand({ dataSourceCopy, rowKeyGen, emits }: Option<DT>) {
|
|
|
51
57
|
const row = tempData[index];
|
|
52
58
|
const col = data?.col || null;
|
|
53
59
|
|
|
60
|
+
if (expand == null) {
|
|
61
|
+
expand = isExpanded(row, col);
|
|
62
|
+
}
|
|
63
|
+
|
|
54
64
|
if (expand) {
|
|
55
65
|
// insert new expanded row
|
|
56
66
|
const newExpandRow: ExpandedRow = {
|
|
@@ -11,6 +11,7 @@ type Option<DT extends Record<string, any>> = {
|
|
|
11
11
|
tableHeaderLast: ShallowRef<PrivateStkTableColumn<DT>[]>;
|
|
12
12
|
tableHeaders: ShallowRef<PrivateStkTableColumn<DT>[][]>;
|
|
13
13
|
rowKeyGen: RowKeyGen;
|
|
14
|
+
maxRowSpan: Map<UniqKey, number>;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
/** 暂存纵向虚拟滚动的数据 */
|
|
@@ -52,7 +53,7 @@ export type VirtualScrollXStore = {
|
|
|
52
53
|
const VUE2_SCROLL_TIMEOUT_MS = 200;
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
|
-
*
|
|
56
|
+
* virtual scroll
|
|
56
57
|
* @param param0
|
|
57
58
|
* @returns
|
|
58
59
|
*/
|
|
@@ -64,8 +65,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
64
65
|
tableHeaderLast,
|
|
65
66
|
tableHeaders,
|
|
66
67
|
rowKeyGen,
|
|
68
|
+
maxRowSpan,
|
|
67
69
|
}: Option<DT>) {
|
|
68
|
-
/** 表头高度 */
|
|
69
70
|
const tableHeaderHeight = ref(props.headerRowHeight);
|
|
70
71
|
|
|
71
72
|
const virtualScroll = ref<VirtualScrollStore>({
|
|
@@ -279,7 +280,6 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
279
280
|
// 先更新滚动条位置记录,其他地方有依赖。(stripe 时ArrowUp/Down滚动依赖)
|
|
280
281
|
virtualScroll.value.scrollTop = sTop;
|
|
281
282
|
|
|
282
|
-
// 非虚拟滚动不往下执行
|
|
283
283
|
if (!virtual_on.value) {
|
|
284
284
|
return;
|
|
285
285
|
}
|
|
@@ -325,6 +325,41 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
325
325
|
endIndex = startIndex + pageSize;
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
if (maxRowSpan.size) {
|
|
329
|
+
// fix startIndex:查找是否有合并行跨越当前startIndex
|
|
330
|
+
let correctedStartIndex = startIndex;
|
|
331
|
+
let correctedEndIndex = endIndex;
|
|
332
|
+
|
|
333
|
+
for (let i = 0; i < startIndex; i++) {
|
|
334
|
+
const row = dataSourceCopyTemp[i];
|
|
335
|
+
if (!row) continue;
|
|
336
|
+
const spanEndIndex = i + (maxRowSpan.get(rowKeyGen(row)) || 1);
|
|
337
|
+
if (spanEndIndex > startIndex) {
|
|
338
|
+
// 找到跨越startIndex的合并行,将startIndex修正为合并行的起始索引
|
|
339
|
+
correctedStartIndex = i;
|
|
340
|
+
if (spanEndIndex > endIndex) {
|
|
341
|
+
// 合并行跨越了整个可视区
|
|
342
|
+
correctedEndIndex = spanEndIndex;
|
|
343
|
+
}
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// fix endIndex:查找是否有合并行跨越当前endIndex
|
|
349
|
+
for (let i = correctedStartIndex; i < endIndex; i++) {
|
|
350
|
+
const row = dataSourceCopyTemp[i];
|
|
351
|
+
if (!row) continue;
|
|
352
|
+
const spanEndIndex = i + (maxRowSpan.get(rowKeyGen(row)) || 1);
|
|
353
|
+
if (spanEndIndex > correctedEndIndex) {
|
|
354
|
+
// 找到跨越endIndex的合并行,将endIndex修正为合并行的结束索引
|
|
355
|
+
correctedEndIndex = Math.max(spanEndIndex, correctedEndIndex);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
startIndex = correctedStartIndex;
|
|
360
|
+
endIndex = correctedEndIndex;
|
|
361
|
+
}
|
|
362
|
+
|
|
328
363
|
if (stripe && startIndex > 0 && startIndex % 2) {
|
|
329
364
|
// 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
|
|
330
365
|
startIndex -= 1; // 奇数-1变成偶数
|
|
@@ -338,7 +373,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
338
373
|
endIndex = Math.min(endIndex, dataLength);
|
|
339
374
|
|
|
340
375
|
if (startIndex >= endIndex) {
|
|
341
|
-
//
|
|
376
|
+
// fallback
|
|
342
377
|
startIndex = endIndex - pageSize;
|
|
343
378
|
}
|
|
344
379
|
|
|
@@ -351,20 +386,20 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
351
386
|
offsetTop = autoRowHeightTop;
|
|
352
387
|
} else {
|
|
353
388
|
if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
|
|
354
|
-
//
|
|
389
|
+
// Not change: not update
|
|
355
390
|
return;
|
|
356
391
|
}
|
|
357
392
|
offsetTop = startIndex * rowHeight;
|
|
358
393
|
}
|
|
359
394
|
|
|
360
395
|
/**
|
|
361
|
-
*
|
|
396
|
+
* en: If scroll faster than one page, roll back
|
|
362
397
|
*/
|
|
363
398
|
if (!optimizeVue2Scroll || sTop <= scrollTop || Math.abs(oldStartIndex - startIndex) >= pageSize) {
|
|
364
|
-
//
|
|
399
|
+
// scroll up
|
|
365
400
|
Object.assign(virtualScroll.value, { startIndex, endIndex, offsetTop });
|
|
366
401
|
} else {
|
|
367
|
-
// vue2
|
|
402
|
+
// vue2 scroll down optimize
|
|
368
403
|
virtualScroll.value.endIndex = endIndex;
|
|
369
404
|
vue2ScrollYTimeout = window.setTimeout(() => {
|
|
370
405
|
Object.assign(virtualScroll.value, { startIndex, offsetTop });
|
|
@@ -374,7 +409,9 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
374
409
|
|
|
375
410
|
let vue2ScrollXTimeout: null | number = null;
|
|
376
411
|
|
|
377
|
-
/**
|
|
412
|
+
/**
|
|
413
|
+
* Calculate virtual scroll parameters based on horizontal scroll bar position
|
|
414
|
+
*/
|
|
378
415
|
function updateVirtualScrollX(sLeft = 0) {
|
|
379
416
|
if (!props.virtualX) return;
|
|
380
417
|
const tableHeaderLastValue = tableHeaderLast.value;
|
|
@@ -384,7 +421,6 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
384
421
|
const { scrollLeft, containerWidth } = virtualScrollX.value;
|
|
385
422
|
let startIndex = 0;
|
|
386
423
|
let offsetLeft = 0;
|
|
387
|
-
/** 列宽累加 */
|
|
388
424
|
let colWidthSum = 0;
|
|
389
425
|
/** 固定左侧列宽 */
|
|
390
426
|
let leftColWidthSum = 0;
|