stk-table-vue 0.7.2 → 0.8.0
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/lib/src/StkTable/StkTable.vue.d.ts +10 -7
- package/lib/src/StkTable/types/index.d.ts +22 -5
- package/lib/src/StkTable/useMergeCells.d.ts +20 -0
- package/lib/src/StkTable/useRowExpand.d.ts +2 -2
- package/lib/src/StkTable/useThDrag.d.ts +5 -6
- package/lib/src/StkTable/useTree.d.ts +2 -2
- package/lib/src/StkTable/useVirtualScroll.d.ts +5 -5
- package/lib/src/StkTable/utils/index.d.ts +2 -1
- package/lib/{style.css → stk-table-vue.css} +6 -0
- package/lib/stk-table-vue.js +209 -101
- package/package.json +5 -5
- package/src/StkTable/StkTable.vue +118 -81
- package/src/StkTable/style.less +11 -6
- package/src/StkTable/types/index.ts +24 -5
- package/src/StkTable/useHighlight.ts +2 -2
- package/src/StkTable/useMergeCells.ts +125 -0
- package/src/StkTable/useRowExpand.ts +2 -2
- package/src/StkTable/useScrollRowByRow.ts +17 -14
- package/src/StkTable/useThDrag.ts +6 -6
- package/src/StkTable/useTree.ts +2 -2
- package/src/StkTable/useVirtualScroll.ts +6 -6
- package/src/StkTable/utils/index.ts +6 -1
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
:key="colKeyGen(col)"
|
|
68
68
|
:data-col-key="colKeyGen(col)"
|
|
69
69
|
:draggable="isHeaderDraggable(col) ? 'true' : 'false'"
|
|
70
|
-
:rowspan="virtualX_on ? 1 : col.
|
|
71
|
-
:colspan="col.
|
|
70
|
+
:rowspan="virtualX_on ? 1 : col.__R_SP__"
|
|
71
|
+
:colspan="col.__C_SP__"
|
|
72
72
|
:style="cellStyleMap[TagType.TH].get(colKeyGen(col))"
|
|
73
73
|
:title="getHeaderTitle(col)"
|
|
74
74
|
:class="[
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
class="table-header-resizer left"
|
|
94
94
|
@mousedown="onThResizeMouseDown($event, col, true)"
|
|
95
95
|
></div>
|
|
96
|
-
<div class="table-header-cell-wrapper" :style="{ '--row-span': virtualX_on ? 1 : col.
|
|
96
|
+
<div class="table-header-cell-wrapper" :style="{ '--row-span': virtualX_on ? 1 : col.__R_SP__ }">
|
|
97
97
|
<component :is="col.customHeaderCell" v-if="col.customHeaderCell" :col="col" :colIndex="colIndex" :rowIndex="rowIndex" />
|
|
98
98
|
<template v-else>
|
|
99
99
|
<slot name="tableHeader" :col="col">
|
|
@@ -142,6 +142,7 @@
|
|
|
142
142
|
@dblclick="onRowDblclick($event, row, getRowIndex(rowIndex))"
|
|
143
143
|
@contextmenu="onRowMenu($event, row, getRowIndex(rowIndex))"
|
|
144
144
|
@mouseover="onTrMouseOver($event, row)"
|
|
145
|
+
@mouseleave="onTrMouseLeave($event)"
|
|
145
146
|
@drop="onTrDrop($event, getRowIndex(rowIndex))"
|
|
146
147
|
>
|
|
147
148
|
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
@@ -155,87 +156,93 @@
|
|
|
155
156
|
</div>
|
|
156
157
|
</td>
|
|
157
158
|
<template v-else>
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
>
|
|
159
|
+
<template v-for="(col, colIndex) in virtualX_columnPart">
|
|
160
|
+
<td
|
|
161
|
+
v-if="!hiddenCellMap[rowKeyGen(row)]?.has(colKeyGen(col))"
|
|
162
|
+
:key="colKeyGen(col)"
|
|
163
|
+
:data-cell-key="cellKeyGen(row, col)"
|
|
164
|
+
:style="cellStyleMap[TagType.TD].get(colKeyGen(col))"
|
|
165
|
+
:class="[
|
|
166
|
+
col.className,
|
|
167
|
+
fixedColClassMap.get(colKeyGen(col)),
|
|
168
|
+
{
|
|
169
|
+
'cell-hover': col.mergeCells && hoverMergedCells.has(cellKeyGen(row, col)),
|
|
170
|
+
'cell-active': col.mergeCells && activeMergedCells.has(cellKeyGen(row, col)),
|
|
171
|
+
'seq-column': col.type === 'seq',
|
|
172
|
+
active: props.cellActive && currentSelectedCellKey === cellKeyGen(row, col),
|
|
173
|
+
expanded:
|
|
174
|
+
col.type === 'expand' && (row.__EXPANDED__ ? colKeyGen(row.__EXPANDED__) === colKeyGen(col) : false),
|
|
175
|
+
'tree-expanded': col.type === 'tree-node' && row.__T_EXPANDED__,
|
|
176
|
+
'drag-row-cell': col.type === 'dragRow',
|
|
177
|
+
},
|
|
178
|
+
]"
|
|
179
|
+
v-bind="mergeCellsWrapper(row, col, rowIndex, colIndex)"
|
|
180
|
+
@click="onCellClick($event, row, col, getRowIndex(rowIndex))"
|
|
181
|
+
@mousedown="onCellMouseDown($event, row, col, getRowIndex(rowIndex))"
|
|
182
|
+
@mouseenter="onCellMouseEnter($event, row, col)"
|
|
183
|
+
@mouseleave="onCellMouseLeave($event, row, col)"
|
|
184
|
+
@mouseover="onCellMouseOver($event, row, col)"
|
|
185
|
+
>
|
|
186
|
+
<template v-if="col.type === 'expand' || col.type === 'tree-node'">
|
|
187
|
+
<div
|
|
188
|
+
class="table-cell-wrapper"
|
|
189
|
+
:title="row?.[col.dataIndex]"
|
|
190
|
+
:style="{ paddingLeft: row.__T_LV__ && row.__T_LV__ * 16 + 'px' }"
|
|
191
|
+
>
|
|
192
|
+
<component
|
|
193
|
+
:is="col.customCell"
|
|
194
|
+
v-if="col.customCell"
|
|
195
|
+
:col="col"
|
|
196
|
+
:row="row"
|
|
197
|
+
:rowIndex="getRowIndex(rowIndex)"
|
|
198
|
+
:colIndex="colIndex"
|
|
199
|
+
:cellValue="row && row[col.dataIndex]"
|
|
200
|
+
:expanded="(row && row.__EXPANDED__) || null"
|
|
201
|
+
:tree-expanded="(row && row.__T_EXPANDED__) || null"
|
|
202
|
+
>
|
|
203
|
+
<template #foldIcon>
|
|
204
|
+
<TriangleIcon></TriangleIcon>
|
|
205
|
+
</template>
|
|
206
|
+
</component>
|
|
207
|
+
<template v-else>
|
|
208
|
+
<TriangleIcon
|
|
209
|
+
v-if="col.type === 'expand' || (col.type === 'tree-node' && row.children !== void 0)"
|
|
210
|
+
@click="triangleClick($event, row, col)"
|
|
211
|
+
/>
|
|
212
|
+
<span :style="col.type === 'tree-node' && !row.children ? 'padding-left: 16px;' : ''">
|
|
213
|
+
{{ row?.[col.dataIndex] ?? '' }}
|
|
214
|
+
</span>
|
|
215
|
+
</template>
|
|
216
|
+
</div>
|
|
217
|
+
</template>
|
|
218
|
+
<template v-else>
|
|
186
219
|
<component
|
|
187
220
|
:is="col.customCell"
|
|
188
221
|
v-if="col.customCell"
|
|
222
|
+
class="table-cell-wrapper"
|
|
189
223
|
:col="col"
|
|
190
224
|
:row="row"
|
|
191
225
|
:rowIndex="getRowIndex(rowIndex)"
|
|
192
226
|
:colIndex="colIndex"
|
|
193
227
|
:cellValue="row && row[col.dataIndex]"
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
<TriangleIcon></TriangleIcon>
|
|
228
|
+
/>
|
|
229
|
+
<div v-else class="table-cell-wrapper" :title="col.type !== 'seq' ? row?.[col.dataIndex] : ''">
|
|
230
|
+
<template v-if="col.type === 'seq'">
|
|
231
|
+
{{ (props.seqConfig.startIndex || 0) + getRowIndex(rowIndex) + 1 }}
|
|
199
232
|
</template>
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
<
|
|
207
|
-
{{ row?.[col.dataIndex] ??
|
|
208
|
-
</
|
|
209
|
-
</
|
|
210
|
-
</
|
|
211
|
-
</
|
|
212
|
-
|
|
213
|
-
<component
|
|
214
|
-
:is="col.customCell"
|
|
215
|
-
v-if="col.customCell"
|
|
216
|
-
class="table-cell-wrapper"
|
|
217
|
-
:col="col"
|
|
218
|
-
:row="row"
|
|
219
|
-
:rowIndex="getRowIndex(rowIndex)"
|
|
220
|
-
:colIndex="colIndex"
|
|
221
|
-
:cellValue="row && row[col.dataIndex]"
|
|
222
|
-
/>
|
|
223
|
-
<div v-else class="table-cell-wrapper" :title="col.type !== 'seq' ? row?.[col.dataIndex] : ''">
|
|
224
|
-
<template v-if="col.type === 'seq'">
|
|
225
|
-
{{ (props.seqConfig.startIndex || 0) + getRowIndex(rowIndex) + 1 }}
|
|
226
|
-
</template>
|
|
227
|
-
<template v-else-if="col.type === 'dragRow'">
|
|
228
|
-
<DragHandle @dragstart="onTrDragStart($event, getRowIndex(rowIndex))" />
|
|
229
|
-
<span>
|
|
230
|
-
{{ row?.[col.dataIndex] ?? '' }}
|
|
231
|
-
</span>
|
|
232
|
-
</template>
|
|
233
|
-
<template v-else>
|
|
234
|
-
{{ row?.[col.dataIndex] ?? getEmptyCellText(col, row) }}
|
|
235
|
-
</template>
|
|
236
|
-
</div>
|
|
237
|
-
</template>
|
|
238
|
-
</td>
|
|
233
|
+
<template v-else-if="col.type === 'dragRow'">
|
|
234
|
+
<DragHandle @dragstart="onTrDragStart($event, getRowIndex(rowIndex))" />
|
|
235
|
+
<span>
|
|
236
|
+
{{ row?.[col.dataIndex] ?? '' }}
|
|
237
|
+
</span>
|
|
238
|
+
</template>
|
|
239
|
+
<template v-else>
|
|
240
|
+
{{ row?.[col.dataIndex] ?? getEmptyCellText(col, row) }}
|
|
241
|
+
</template>
|
|
242
|
+
</div>
|
|
243
|
+
</template>
|
|
244
|
+
</td>
|
|
245
|
+
</template>
|
|
239
246
|
</template>
|
|
240
247
|
</tr>
|
|
241
248
|
<tr v-if="virtual_on && !isSRBRActive" :style="`height: ${virtual_offsetBottom}px`"></tr>
|
|
@@ -273,6 +280,7 @@ import {
|
|
|
273
280
|
StkTableColumn,
|
|
274
281
|
TagType,
|
|
275
282
|
TreeConfig,
|
|
283
|
+
UniqKey,
|
|
276
284
|
UniqKeyProp,
|
|
277
285
|
} from './types/index';
|
|
278
286
|
import { useAutoResize } from './useAutoResize';
|
|
@@ -288,6 +296,7 @@ import { useThDrag } from './useThDrag';
|
|
|
288
296
|
import { useTrDrag } from './useTrDrag';
|
|
289
297
|
import { useTree } from './useTree';
|
|
290
298
|
import { useVirtualScroll } from './useVirtualScroll';
|
|
299
|
+
import { useMergeCells } from './useMergeCells';
|
|
291
300
|
import { createStkTableId, getCalculatedColWidth, getColWidth } from './utils/constRefUtils';
|
|
292
301
|
import { howDeepTheHeader, isEmptyValue, tableSort, transformWidthToStr } from './utils/index';
|
|
293
302
|
|
|
@@ -454,6 +463,7 @@ const props = withDefaults(
|
|
|
454
463
|
columns: () => [],
|
|
455
464
|
dataSource: () => [],
|
|
456
465
|
rowKey: '',
|
|
466
|
+
colKey: void 0,
|
|
457
467
|
emptyCellText: '--',
|
|
458
468
|
noDataFull: false,
|
|
459
469
|
showNoData: true,
|
|
@@ -652,9 +662,9 @@ const currentRow = shallowRef<DT>();
|
|
|
652
662
|
* 保存当前选中行的key<br>
|
|
653
663
|
* 原因:vue3 不用ref包dataSource时,row为原始对象,与currentItem(Ref)相比会不相等。
|
|
654
664
|
*/
|
|
655
|
-
const currentRowKey = ref<
|
|
665
|
+
const currentRowKey = ref<UniqKey | undefined>();
|
|
656
666
|
/** 当前选中的单元格key */
|
|
657
|
-
const currentSelectedCellKey = ref<
|
|
667
|
+
const currentSelectedCellKey = ref<string | undefined>();
|
|
658
668
|
/** 当前hover行 */
|
|
659
669
|
let currentHoverRow: DT | null = null;
|
|
660
670
|
/** 当前hover的行的key */
|
|
@@ -680,7 +690,7 @@ const sortSwitchOrder: Order[] = [null, 'desc', 'asc'];
|
|
|
680
690
|
* ]
|
|
681
691
|
* ```
|
|
682
692
|
*/
|
|
683
|
-
const tableHeaders = shallowRef<
|
|
693
|
+
const tableHeaders = shallowRef<PrivateStkTableColumn<DT>[][]>([]);
|
|
684
694
|
|
|
685
695
|
/**
|
|
686
696
|
* 用于计算多级表头的tableHeaders。模拟rowSpan 位置的辅助数组。用于计算固定列。
|
|
@@ -818,6 +828,14 @@ const { toggleExpandRow, setRowExpand } = useRowExpand({ dataSourceCopy, rowKeyG
|
|
|
818
828
|
|
|
819
829
|
const { toggleTreeNode, setTreeExpand, flatTreeData } = useTree({ props, dataSourceCopy, rowKeyGen, emits });
|
|
820
830
|
|
|
831
|
+
const { hiddenCellMap, mergeCellsWrapper, hoverMergedCells, updateHoverMergedCells, activeMergedCells, updateActiveMergedCells } = useMergeCells({
|
|
832
|
+
props,
|
|
833
|
+
tableHeaderLast,
|
|
834
|
+
rowKeyGen,
|
|
835
|
+
colKeyGen,
|
|
836
|
+
virtual_dataSourcePart,
|
|
837
|
+
});
|
|
838
|
+
|
|
821
839
|
watch(
|
|
822
840
|
() => props.columns,
|
|
823
841
|
() => {
|
|
@@ -993,10 +1011,10 @@ function dealColumns() {
|
|
|
993
1011
|
const rowSpan = col.children ? 1 : maxDeep - depth + 1;
|
|
994
1012
|
const colSpan = colChildrenLen;
|
|
995
1013
|
if (rowSpan > 1) {
|
|
996
|
-
col.
|
|
1014
|
+
col.__R_SP__ = rowSpan;
|
|
997
1015
|
}
|
|
998
1016
|
if (colSpan > 1) {
|
|
999
|
-
col.
|
|
1017
|
+
col.__C_SP__ = colSpan;
|
|
1000
1018
|
}
|
|
1001
1019
|
|
|
1002
1020
|
allChildrenLen += colChildrenLen;
|
|
@@ -1154,9 +1172,11 @@ function onRowClick(e: MouseEvent, row: DT, rowIndex: number) {
|
|
|
1154
1172
|
// 点击同一行,取消当前选中行。
|
|
1155
1173
|
currentRow.value = void 0;
|
|
1156
1174
|
currentRowKey.value = void 0;
|
|
1175
|
+
updateActiveMergedCells(true);
|
|
1157
1176
|
} else {
|
|
1158
1177
|
currentRow.value = row;
|
|
1159
1178
|
currentRowKey.value = rowKeyGen(row);
|
|
1179
|
+
updateActiveMergedCells();
|
|
1160
1180
|
}
|
|
1161
1181
|
emits('current-change', e, row, { select: !isCurrentRow });
|
|
1162
1182
|
}
|
|
@@ -1337,7 +1357,24 @@ function onTableScroll(e: Event) {
|
|
|
1337
1357
|
function onTrMouseOver(_e: MouseEvent, row: DT) {
|
|
1338
1358
|
if (currentHoverRow === row) return;
|
|
1339
1359
|
currentHoverRow = row;
|
|
1340
|
-
|
|
1360
|
+
const rowKey = rowKeyGen(row);
|
|
1361
|
+
if (props.showTrHoverClass) {
|
|
1362
|
+
currentHoverRowKey.value = rowKey;
|
|
1363
|
+
}
|
|
1364
|
+
if (props.rowHover) {
|
|
1365
|
+
updateHoverMergedCells(rowKey);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
function onTrMouseLeave(e: MouseEvent) {
|
|
1370
|
+
if ((e.target as HTMLTableRowElement).tagName !== 'TR') return;
|
|
1371
|
+
currentHoverRow = null;
|
|
1372
|
+
if (props.showTrHoverClass) {
|
|
1373
|
+
currentHoverRowKey.value = null;
|
|
1374
|
+
}
|
|
1375
|
+
if (props.rowHover) {
|
|
1376
|
+
updateHoverMergedCells(void 0);
|
|
1377
|
+
}
|
|
1341
1378
|
}
|
|
1342
1379
|
|
|
1343
1380
|
/**
|
package/src/StkTable/style.less
CHANGED
|
@@ -151,7 +151,6 @@
|
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
/* 斑马纹*/
|
|
155
154
|
&.stripe {
|
|
156
155
|
&:not(.vt-on) .stk-tbody-main tr:nth-child(even) {
|
|
157
156
|
background-color: var(--stripe-bgc);
|
|
@@ -557,11 +556,17 @@
|
|
|
557
556
|
transition: transform 0.2s ease;
|
|
558
557
|
}
|
|
559
558
|
|
|
560
|
-
&:hover {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
border-left: 5px solid var(--fold-icon-hover-color);
|
|
564
|
-
}
|
|
559
|
+
&:hover::before {
|
|
560
|
+
border-left: 5px solid var(--fold-icon-hover-color);
|
|
565
561
|
}
|
|
566
562
|
}
|
|
563
|
+
|
|
564
|
+
td.cell-hover {
|
|
565
|
+
background-color: var(--tr-hover-bgc);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
td.cell-active {
|
|
569
|
+
background-color: var(--tr-active-bgc);
|
|
570
|
+
}
|
|
571
|
+
|
|
567
572
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component, ConcreteComponent } from 'vue';
|
|
1
|
+
import { Component, ComputedRef, ConcreteComponent } from 'vue';
|
|
2
2
|
|
|
3
3
|
/** 排序方式,asc-正序,desc-倒序,null-默认顺序 */
|
|
4
4
|
export type Order = null | 'asc' | 'desc';
|
|
@@ -26,6 +26,15 @@ export type CustomHeaderCellProps<T extends Record<string, any>> = {
|
|
|
26
26
|
colIndex: number;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
export type MergeCellsParam<T extends Record<string, any>> = {
|
|
30
|
+
row: T;
|
|
31
|
+
col: StkTableColumn<T>;
|
|
32
|
+
rowIndex: number;
|
|
33
|
+
colIndex: number;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type MergeCellsFn<T extends Record<string, any>> = (data: MergeCellsParam<T>) => { rowspan?: number; colspan?: number } | undefined;
|
|
37
|
+
|
|
29
38
|
/**
|
|
30
39
|
* 自定义渲染单元格
|
|
31
40
|
*
|
|
@@ -82,8 +91,6 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
82
91
|
sortConfig?: Pick<SortConfig<T>, 'emptyToBottom' | 'stringLocaleCompare'>;
|
|
83
92
|
/** 固定列 */
|
|
84
93
|
fixed?: 'left' | 'right' | null;
|
|
85
|
-
/** private */ rowSpan?: number;
|
|
86
|
-
/** private */ colSpan?: number;
|
|
87
94
|
/**
|
|
88
95
|
* 自定义 td 渲染内容。
|
|
89
96
|
*
|
|
@@ -106,17 +113,23 @@ export type StkTableColumn<T extends Record<string, any>> = {
|
|
|
106
113
|
customHeaderCell?: CustomCell<CustomHeaderCellProps<T>, T>;
|
|
107
114
|
/** 二级表头 */
|
|
108
115
|
children?: StkTableColumn<T>[];
|
|
116
|
+
/** 单元格合并 */
|
|
117
|
+
mergeCells?: MergeCellsFn<T>;
|
|
109
118
|
};
|
|
110
119
|
|
|
111
120
|
/** private StkTableColumn type. Add some private key */
|
|
112
121
|
export type PrivateStkTableColumn<T extends Record<string, any>> = StkTableColumn<T> & {
|
|
122
|
+
/** header rowSpan */
|
|
123
|
+
__R_SP__?: number;
|
|
124
|
+
/** header colSpan */
|
|
125
|
+
__C_SP__?: number;
|
|
113
126
|
/**
|
|
114
|
-
*
|
|
127
|
+
* parent not ref
|
|
115
128
|
* @private
|
|
116
129
|
*/
|
|
117
130
|
__PARENT__?: StkTableColumn<T> | null;
|
|
118
131
|
/**
|
|
119
|
-
*
|
|
132
|
+
* Save the calculated width. Used for horizontal virtual scrolling.
|
|
120
133
|
* @private
|
|
121
134
|
*/
|
|
122
135
|
__WIDTH__?: number;
|
|
@@ -258,3 +271,9 @@ export type AutoRowHeightConfig<DT> = {
|
|
|
258
271
|
export type ColResizableConfig<DT extends Record<string, any>> = {
|
|
259
272
|
disabled: (col: StkTableColumn<DT>) => boolean;
|
|
260
273
|
};
|
|
274
|
+
|
|
275
|
+
export type RowKeyGen = (row: any) => UniqKey;
|
|
276
|
+
|
|
277
|
+
export type ColKeyGen = ComputedRef<(col: StkTableColumn<any>) => UniqKey>;
|
|
278
|
+
|
|
279
|
+
export type CellKeyGen = (row: any, col: StkTableColumn<any>) => string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// import { interpolateRgb } from 'd3-interpolate';
|
|
2
1
|
import { Ref, computed } from 'vue';
|
|
3
2
|
import { HIGHLIGHT_CELL_CLASS, HIGHLIGHT_COLOR, HIGHLIGHT_DURATION, HIGHLIGHT_ROW_CLASS } from './const';
|
|
4
3
|
import { HighlightConfig, UniqKey } from './types';
|
|
5
4
|
import { HighlightDimCellOption, HighlightDimRowOption } from './types/highlightDimOptions';
|
|
5
|
+
import { pureCellKeyGen } from './utils';
|
|
6
6
|
|
|
7
7
|
type Params = {
|
|
8
8
|
props: any;
|
|
@@ -108,7 +108,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
108
108
|
* @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。
|
|
109
109
|
*/
|
|
110
110
|
function setHighlightDimCell(rowKeyValue: UniqKey, colKeyValue: string, option: HighlightDimCellOption = {}) {
|
|
111
|
-
const cellEl = tableContainerRef.value?.querySelector<HTMLElement>(`[data-cell-key="${rowKeyValue
|
|
111
|
+
const cellEl = tableContainerRef.value?.querySelector<HTMLElement>(`[data-cell-key="${pureCellKeyGen(rowKeyValue, colKeyValue)}"]`);
|
|
112
112
|
if (!cellEl) return;
|
|
113
113
|
const { className, method, duration, keyframe } = {
|
|
114
114
|
className: HIGHLIGHT_CELL_CLASS,
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { ref, ShallowRef, watch } from 'vue';
|
|
2
|
+
import { ColKeyGen, MergeCellsParam, PrivateStkTableColumn, RowKeyGen, UniqKey } from './types';
|
|
3
|
+
import { pureCellKeyGen } from './utils';
|
|
4
|
+
|
|
5
|
+
export function useMergeCells({
|
|
6
|
+
props,
|
|
7
|
+
tableHeaderLast,
|
|
8
|
+
rowKeyGen,
|
|
9
|
+
colKeyGen,
|
|
10
|
+
virtual_dataSourcePart,
|
|
11
|
+
}: {
|
|
12
|
+
props: any;
|
|
13
|
+
tableHeaderLast: ShallowRef<PrivateStkTableColumn<any>[]>;
|
|
14
|
+
rowKeyGen: RowKeyGen;
|
|
15
|
+
colKeyGen: ColKeyGen;
|
|
16
|
+
virtual_dataSourcePart: ShallowRef<any[]>;
|
|
17
|
+
}) {
|
|
18
|
+
/**
|
|
19
|
+
* which cell need be hidden
|
|
20
|
+
* - key: rowKey
|
|
21
|
+
* - value: colKey Set
|
|
22
|
+
*/
|
|
23
|
+
const hiddenCellMap = ref<Record<UniqKey, Set<UniqKey>>>({});
|
|
24
|
+
/**
|
|
25
|
+
* hover other row and rowspan cell should be highlighted
|
|
26
|
+
* - key: rowKey
|
|
27
|
+
* - value: cellKey Set
|
|
28
|
+
*/
|
|
29
|
+
const hoverRowMap = ref<Record<UniqKey, Set<string>>>({});
|
|
30
|
+
|
|
31
|
+
/** hover current row , which rowspan cells should be highlight */
|
|
32
|
+
const hoverMergedCells = ref(new Set<string>());
|
|
33
|
+
/** click current row , which rowspan cells should be highlight */
|
|
34
|
+
const activeMergedCells = ref(new Set<string>());
|
|
35
|
+
|
|
36
|
+
watch([virtual_dataSourcePart, tableHeaderLast], () => {
|
|
37
|
+
hiddenCellMap.value = {};
|
|
38
|
+
hoverRowMap.value = {};
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/** 抽象隐藏单元格的逻辑 */
|
|
42
|
+
function hideCells(rowKey: UniqKey, startIndex: number, count: number, isSelfRow = false, mergeCellKey: string) {
|
|
43
|
+
for (let i = startIndex; i < startIndex + count; i++) {
|
|
44
|
+
if (!isSelfRow || i !== startIndex) {
|
|
45
|
+
// 自己不需要隐藏
|
|
46
|
+
const nextCol = tableHeaderLast.value[i];
|
|
47
|
+
if (!nextCol) break;
|
|
48
|
+
const nextColKey = colKeyGen.value(nextCol);
|
|
49
|
+
if (!hiddenCellMap.value[rowKey]) hiddenCellMap.value[rowKey] = new Set();
|
|
50
|
+
hiddenCellMap.value[rowKey].add(nextColKey);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// if other row hovered, the rowspan cell need to be highlight
|
|
54
|
+
if (!hoverRowMap.value[rowKey]) hoverRowMap.value[rowKey] = new Set();
|
|
55
|
+
hoverRowMap.value[rowKey].add(mergeCellKey);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* calculate colspan and rowspan
|
|
61
|
+
* @param row
|
|
62
|
+
* @param col
|
|
63
|
+
* @param rowIndex
|
|
64
|
+
* @param colIndex
|
|
65
|
+
* @returns
|
|
66
|
+
*/
|
|
67
|
+
function mergeCellsWrapper(
|
|
68
|
+
row: MergeCellsParam<any>['row'],
|
|
69
|
+
col: MergeCellsParam<any>['col'],
|
|
70
|
+
rowIndex: MergeCellsParam<any>['rowIndex'],
|
|
71
|
+
colIndex: MergeCellsParam<any>['colIndex'],
|
|
72
|
+
): { colspan?: number; rowspan?: number } | undefined {
|
|
73
|
+
if (!col.mergeCells) return;
|
|
74
|
+
|
|
75
|
+
let { colspan, rowspan } = col.mergeCells({ row, col, rowIndex, colIndex }) || {};
|
|
76
|
+
|
|
77
|
+
// default colspan and rowspan is 1
|
|
78
|
+
colspan = colspan || 1;
|
|
79
|
+
rowspan = rowspan || 1;
|
|
80
|
+
|
|
81
|
+
if (colspan === 1 && rowspan === 1) return;
|
|
82
|
+
|
|
83
|
+
const rowKey = rowKeyGen(row);
|
|
84
|
+
const colKey = colKeyGen.value(col);
|
|
85
|
+
const dataSourceSlice = virtual_dataSourcePart.value.slice();
|
|
86
|
+
const curColIndex = tableHeaderLast.value.findIndex(item => colKeyGen.value(item) === colKey);
|
|
87
|
+
const curRowIndex = dataSourceSlice.findIndex(item => rowKeyGen(item) === rowKey);
|
|
88
|
+
const mergedCellKey = pureCellKeyGen(rowKey, colKey);
|
|
89
|
+
|
|
90
|
+
if (curRowIndex === -1) return;
|
|
91
|
+
|
|
92
|
+
for (let i = curRowIndex; i < curRowIndex + rowspan; i++) {
|
|
93
|
+
const row = dataSourceSlice[i];
|
|
94
|
+
if (!row) break;
|
|
95
|
+
const rKey = rowKeyGen(row);
|
|
96
|
+
const isSelfRow = i === curRowIndex;
|
|
97
|
+
hideCells(rKey, curColIndex, colspan, isSelfRow, mergedCellKey);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return { colspan, rowspan };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function updateHoverMergedCells(rowKey: UniqKey | undefined) {
|
|
104
|
+
const set = rowKey === void 0 ? null : hoverRowMap.value[rowKey];
|
|
105
|
+
hoverMergedCells.value = set || new Set();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function updateActiveMergedCells(clear?: boolean) {
|
|
109
|
+
if (!props.rowActive) return;
|
|
110
|
+
if (clear) {
|
|
111
|
+
activeMergedCells.value.clear();
|
|
112
|
+
} else {
|
|
113
|
+
activeMergedCells.value = new Set(hoverMergedCells.value);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
hiddenCellMap,
|
|
119
|
+
mergeCellsWrapper,
|
|
120
|
+
hoverMergedCells,
|
|
121
|
+
updateHoverMergedCells,
|
|
122
|
+
activeMergedCells,
|
|
123
|
+
updateActiveMergedCells,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ShallowRef } from 'vue';
|
|
2
|
-
import { ExpandedRow, PrivateRowDT, StkTableColumn, UniqKey } from './types';
|
|
2
|
+
import { ExpandedRow, PrivateRowDT, RowKeyGen, StkTableColumn, UniqKey } from './types';
|
|
3
3
|
import { EXPANDED_ROW_KEY_PREFIX } from './const';
|
|
4
4
|
type DT = PrivateRowDT;
|
|
5
5
|
type Option<DT extends Record<string, any>> = {
|
|
6
|
-
rowKeyGen:
|
|
6
|
+
rowKeyGen: RowKeyGen;
|
|
7
7
|
dataSourceCopy: ShallowRef<DT[]>;
|
|
8
8
|
emits: any;
|
|
9
9
|
};
|
|
@@ -8,8 +8,10 @@ type Params = {
|
|
|
8
8
|
export function useScrollRowByRow({ props, tableContainerRef }: Params) {
|
|
9
9
|
let isMouseDown = false;
|
|
10
10
|
let isAddListeners = false;
|
|
11
|
+
/** record the last scroll bar position */
|
|
12
|
+
let lastScrollTop = 0;
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
/** record is the scroll bar is dragging */
|
|
13
15
|
const isDragScroll = ref(false);
|
|
14
16
|
const onlyDragScroll = computed(() => props.scrollRowByRow === 'scrollbar');
|
|
15
17
|
|
|
@@ -21,16 +23,13 @@ export function useScrollRowByRow({ props, tableContainerRef }: Params) {
|
|
|
21
23
|
return props.scrollRowByRow;
|
|
22
24
|
});
|
|
23
25
|
|
|
24
|
-
watch(
|
|
25
|
-
()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
);
|
|
26
|
+
watch(onlyDragScroll, v => {
|
|
27
|
+
if (v) {
|
|
28
|
+
addEventListener();
|
|
29
|
+
} else {
|
|
30
|
+
removeEventListener();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
34
33
|
|
|
35
34
|
onMounted(() => {
|
|
36
35
|
addEventListener();
|
|
@@ -59,17 +58,21 @@ export function useScrollRowByRow({ props, tableContainerRef }: Params) {
|
|
|
59
58
|
isAddListeners = false;
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
function handleMouseDown() {
|
|
61
|
+
function handleMouseDown(e: Event) {
|
|
63
62
|
isMouseDown = true;
|
|
63
|
+
lastScrollTop = (e.target as HTMLElement).scrollTop;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function handleMouseUp() {
|
|
67
67
|
isMouseDown = false;
|
|
68
68
|
isDragScroll.value = false;
|
|
69
|
+
lastScrollTop = 0;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
function handleScroll() {
|
|
72
|
-
|
|
72
|
+
function handleScroll(e: Event) {
|
|
73
|
+
const scrollTop = (e.target as HTMLElement).scrollTop;
|
|
74
|
+
// if scrollTop === lastScrollTop means horizontal scroll
|
|
75
|
+
if (!isMouseDown || scrollTop === lastScrollTop) return;
|
|
73
76
|
isDragScroll.value = true;
|
|
74
77
|
}
|
|
75
78
|
return { isSRBRActive, isDragScroll };
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { computed
|
|
2
|
-
import {
|
|
1
|
+
import { computed } from 'vue';
|
|
2
|
+
import { ColKeyGen, StkTableColumn } from './types';
|
|
3
3
|
import { isEmptyValue } from './utils';
|
|
4
4
|
|
|
5
|
-
type Params
|
|
5
|
+
type Params = {
|
|
6
6
|
props: any;
|
|
7
7
|
emits: any;
|
|
8
|
-
colKeyGen:
|
|
8
|
+
colKeyGen: ColKeyGen;
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
11
11
|
* 列顺序拖动
|
|
12
12
|
* @returns
|
|
13
13
|
*/
|
|
14
|
-
export function useThDrag
|
|
14
|
+
export function useThDrag({ props, emits, colKeyGen }: Params) {
|
|
15
15
|
const findParentTH = (e: DragEvent) => (e.target as HTMLElement).closest('th');
|
|
16
16
|
|
|
17
17
|
const dragConfig = computed(() => {
|
|
@@ -97,6 +97,6 @@ export function useThDrag<DT extends Record<string, any>>({ props, emits, colKey
|
|
|
97
97
|
onThDragOver,
|
|
98
98
|
onThDrop,
|
|
99
99
|
/** 是否可拖拽 */
|
|
100
|
-
isHeaderDraggable: (col: StkTableColumn<
|
|
100
|
+
isHeaderDraggable: (col: StkTableColumn<any>) => dragConfig.value.draggable && !dragConfig.value.disabled(col),
|
|
101
101
|
};
|
|
102
102
|
}
|