stk-table-vue 0.7.2 → 0.8.1

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.
@@ -52,7 +52,6 @@
52
52
  'fixed-mode': props.fixedMode,
53
53
  }"
54
54
  >
55
- <!-- transform: virtualX_on ? `translateX(${virtualScrollX.offsetLeft}px)` : null, 用transform控制虚拟滚动左边距,sticky会有问题 -->
56
55
  <thead v-if="!headless" ref="theadRef">
57
56
  <tr v-for="(row, rowIndex) in tableHeaders" :key="rowIndex" @contextmenu="onHeaderMenu($event)">
58
57
  <!-- 这个th用于横向虚拟滚动表格左边距,width、maxWidth 用于兼容低版本浏览器 -->
@@ -67,8 +66,8 @@
67
66
  :key="colKeyGen(col)"
68
67
  :data-col-key="colKeyGen(col)"
69
68
  :draggable="isHeaderDraggable(col) ? 'true' : 'false'"
70
- :rowspan="virtualX_on ? 1 : col.rowSpan"
71
- :colspan="col.colSpan"
69
+ :rowspan="virtualX_on ? 1 : col.__R_SP__"
70
+ :colspan="col.__C_SP__"
72
71
  :style="cellStyleMap[TagType.TH].get(colKeyGen(col))"
73
72
  :title="getHeaderTitle(col)"
74
73
  :class="[
@@ -93,7 +92,7 @@
93
92
  class="table-header-resizer left"
94
93
  @mousedown="onThResizeMouseDown($event, col, true)"
95
94
  ></div>
96
- <div class="table-header-cell-wrapper" :style="{ '--row-span': virtualX_on ? 1 : col.rowSpan }">
95
+ <div class="table-header-cell-wrapper" :style="{ '--row-span': virtualX_on ? 1 : col.__R_SP__ }">
97
96
  <component :is="col.customHeaderCell" v-if="col.customHeaderCell" :col="col" :colIndex="colIndex" :rowIndex="rowIndex" />
98
97
  <template v-else>
99
98
  <slot name="tableHeader" :col="col">
@@ -110,9 +109,6 @@
110
109
  </tr>
111
110
  </thead>
112
111
 
113
- <!-- 用于虚拟滚动表格内容定位 @deprecated 有兼容问题-->
114
- <!-- <tbody v-if="virtual_on" :style="{ height: `${virtualScroll.offsetTop}px` }"></tbody> -->
115
- <!-- <tbody :style="{ transform: `translateY(${virtualScroll.offsetTop}px)` }"> -->
116
112
  <tbody class="stk-tbody-main" @dragover="onTrDragOver" @dragenter="onTrDragEnter" @dragend="onTrDragEnd">
117
113
  <tr v-if="virtual_on && !isSRBRActive" :style="`height:${virtualScroll.offsetTop}px`" class="padding-top-tr">
118
114
  <!--这个td用于配合虚拟滚动的th对应,防止列错位-->
@@ -142,6 +138,7 @@
142
138
  @dblclick="onRowDblclick($event, row, getRowIndex(rowIndex))"
143
139
  @contextmenu="onRowMenu($event, row, getRowIndex(rowIndex))"
144
140
  @mouseover="onTrMouseOver($event, row)"
141
+ @mouseleave="onTrMouseLeave($event)"
145
142
  @drop="onTrDrop($event, getRowIndex(rowIndex))"
146
143
  >
147
144
  <!--这个td用于配合虚拟滚动的th对应,防止列错位-->
@@ -155,87 +152,93 @@
155
152
  </div>
156
153
  </td>
157
154
  <template v-else>
158
- <td
159
- v-for="(col, colIndex) in virtualX_columnPart"
160
- :key="colKeyGen(col)"
161
- :data-cell-key="cellKeyGen(row, col)"
162
- :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"
163
- :class="[
164
- col.className,
165
- fixedColClassMap.get(colKeyGen(col)),
166
- {
167
- 'seq-column': col.type === 'seq',
168
- active: currentSelectedCellKey === cellKeyGen(row, col),
169
- expanded: col.type === 'expand' && (row.__EXPANDED__ ? colKeyGen(row.__EXPANDED__) === colKeyGen(col) : false),
170
- 'tree-expanded': col.type === 'tree-node' && row.__T_EXPANDED__,
171
- 'drag-row-cell': col.type === 'dragRow',
172
- },
173
- ]"
174
- @click="onCellClick($event, row, col, getRowIndex(rowIndex))"
175
- @mousedown="onCellMouseDown($event, row, col, getRowIndex(rowIndex))"
176
- @mouseenter="onCellMouseEnter($event, row, col)"
177
- @mouseleave="onCellMouseLeave($event, row, col)"
178
- @mouseover="onCellMouseOver($event, row, col)"
179
- >
180
- <template v-if="col.type === 'expand' || col.type === 'tree-node'">
181
- <div
182
- class="table-cell-wrapper"
183
- :title="row?.[col.dataIndex]"
184
- :style="{ paddingLeft: row.__T_LV__ && row.__T_LV__ * 16 + 'px' }"
185
- >
155
+ <template v-for="(col, colIndex) in virtualX_columnPart">
156
+ <td
157
+ v-if="!hiddenCellMap[rowKeyGen(row)]?.has(colKeyGen(col))"
158
+ :key="colKeyGen(col)"
159
+ :data-cell-key="cellKeyGen(row, col)"
160
+ :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"
161
+ :class="[
162
+ col.className,
163
+ fixedColClassMap.get(colKeyGen(col)),
164
+ {
165
+ 'cell-hover': col.mergeCells && hoverMergedCells.has(cellKeyGen(row, col)),
166
+ 'cell-active': col.mergeCells && activeMergedCells.has(cellKeyGen(row, col)),
167
+ 'seq-column': col.type === 'seq',
168
+ active: props.cellActive && currentSelectedCellKey === cellKeyGen(row, col),
169
+ expanded:
170
+ col.type === 'expand' && (row.__EXPANDED__ ? colKeyGen(row.__EXPANDED__) === colKeyGen(col) : false),
171
+ 'tree-expanded': col.type === 'tree-node' && row.__T_EXPANDED__,
172
+ 'drag-row-cell': col.type === 'dragRow',
173
+ },
174
+ ]"
175
+ v-bind="mergeCellsWrapper(row, col, rowIndex, colIndex)"
176
+ @click="onCellClick($event, row, col, getRowIndex(rowIndex))"
177
+ @mousedown="onCellMouseDown($event, row, col, getRowIndex(rowIndex))"
178
+ @mouseenter="onCellMouseEnter($event, row, col)"
179
+ @mouseleave="onCellMouseLeave($event, row, col)"
180
+ @mouseover="onCellMouseOver($event, row, col)"
181
+ >
182
+ <template v-if="col.type === 'expand' || col.type === 'tree-node'">
183
+ <div
184
+ class="table-cell-wrapper"
185
+ :title="row?.[col.dataIndex]"
186
+ :style="{ paddingLeft: row.__T_LV__ && row.__T_LV__ * 16 + 'px' }"
187
+ >
188
+ <component
189
+ :is="col.customCell"
190
+ v-if="col.customCell"
191
+ :col="col"
192
+ :row="row"
193
+ :rowIndex="getRowIndex(rowIndex)"
194
+ :colIndex="colIndex"
195
+ :cellValue="row && row[col.dataIndex]"
196
+ :expanded="(row && row.__EXPANDED__) || null"
197
+ :tree-expanded="(row && row.__T_EXPANDED__) || null"
198
+ >
199
+ <template #foldIcon>
200
+ <TriangleIcon></TriangleIcon>
201
+ </template>
202
+ </component>
203
+ <template v-else>
204
+ <TriangleIcon
205
+ v-if="col.type === 'expand' || (col.type === 'tree-node' && row.children !== void 0)"
206
+ @click="triangleClick($event, row, col)"
207
+ />
208
+ <span :style="col.type === 'tree-node' && !row.children ? 'padding-left: 16px;' : ''">
209
+ {{ row?.[col.dataIndex] ?? '' }}
210
+ </span>
211
+ </template>
212
+ </div>
213
+ </template>
214
+ <template v-else>
186
215
  <component
187
216
  :is="col.customCell"
188
217
  v-if="col.customCell"
218
+ class="table-cell-wrapper"
189
219
  :col="col"
190
220
  :row="row"
191
221
  :rowIndex="getRowIndex(rowIndex)"
192
222
  :colIndex="colIndex"
193
223
  :cellValue="row && row[col.dataIndex]"
194
- :expanded="(row && row.__EXPANDED__) || null"
195
- :tree-expanded="(row && row.__T_EXPANDED__) || null"
196
- >
197
- <template #foldIcon>
198
- <TriangleIcon></TriangleIcon>
224
+ />
225
+ <div v-else class="table-cell-wrapper" :title="col.type !== 'seq' ? row?.[col.dataIndex] : ''">
226
+ <template v-if="col.type === 'seq'">
227
+ {{ (props.seqConfig.startIndex || 0) + getRowIndex(rowIndex) + 1 }}
199
228
  </template>
200
- </component>
201
- <template v-else>
202
- <TriangleIcon
203
- v-if="col.type === 'expand' || (col.type === 'tree-node' && row.children !== void 0)"
204
- @click="triangleClick($event, row, col)"
205
- />
206
- <span :style="col.type === 'tree-node' && !row.children ? 'padding-left: 16px;' : ''">
207
- {{ row?.[col.dataIndex] ?? '' }}
208
- </span>
209
- </template>
210
- </div>
211
- </template>
212
- <template v-else>
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>
229
+ <template v-else-if="col.type === 'dragRow'">
230
+ <DragHandle @dragstart="onTrDragStart($event, getRowIndex(rowIndex))" />
231
+ <span>
232
+ {{ row?.[col.dataIndex] ?? '' }}
233
+ </span>
234
+ </template>
235
+ <template v-else>
236
+ {{ row?.[col.dataIndex] ?? getEmptyCellText(col, row) }}
237
+ </template>
238
+ </div>
239
+ </template>
240
+ </td>
241
+ </template>
239
242
  </template>
240
243
  </tr>
241
244
  <tr v-if="virtual_on && !isSRBRActive" :style="`height: ${virtual_offsetBottom}px`"></tr>
@@ -273,6 +276,7 @@ import {
273
276
  StkTableColumn,
274
277
  TagType,
275
278
  TreeConfig,
279
+ UniqKey,
276
280
  UniqKeyProp,
277
281
  } from './types/index';
278
282
  import { useAutoResize } from './useAutoResize';
@@ -288,6 +292,7 @@ import { useThDrag } from './useThDrag';
288
292
  import { useTrDrag } from './useTrDrag';
289
293
  import { useTree } from './useTree';
290
294
  import { useVirtualScroll } from './useVirtualScroll';
295
+ import { useMergeCells } from './useMergeCells';
291
296
  import { createStkTableId, getCalculatedColWidth, getColWidth } from './utils/constRefUtils';
292
297
  import { howDeepTheHeader, isEmptyValue, tableSort, transformWidthToStr } from './utils/index';
293
298
 
@@ -454,6 +459,7 @@ const props = withDefaults(
454
459
  columns: () => [],
455
460
  dataSource: () => [],
456
461
  rowKey: '',
462
+ colKey: void 0,
457
463
  emptyCellText: '--',
458
464
  noDataFull: false,
459
465
  showNoData: true,
@@ -652,9 +658,9 @@ const currentRow = shallowRef<DT>();
652
658
  * 保存当前选中行的key<br>
653
659
  * 原因:vue3 不用ref包dataSource时,row为原始对象,与currentItem(Ref)相比会不相等。
654
660
  */
655
- const currentRowKey = ref<any>(void 0);
661
+ const currentRowKey = ref<UniqKey | undefined>();
656
662
  /** 当前选中的单元格key */
657
- const currentSelectedCellKey = ref<any>(void 0);
663
+ const currentSelectedCellKey = ref<string | undefined>();
658
664
  /** 当前hover行 */
659
665
  let currentHoverRow: DT | null = null;
660
666
  /** 当前hover的行的key */
@@ -680,7 +686,7 @@ const sortSwitchOrder: Order[] = [null, 'desc', 'asc'];
680
686
  * ]
681
687
  * ```
682
688
  */
683
- const tableHeaders = shallowRef<StkTableColumn<DT>[][]>([]);
689
+ const tableHeaders = shallowRef<PrivateStkTableColumn<DT>[][]>([]);
684
690
 
685
691
  /**
686
692
  * 用于计算多级表头的tableHeaders。模拟rowSpan 位置的辅助数组。用于计算固定列。
@@ -818,6 +824,14 @@ const { toggleExpandRow, setRowExpand } = useRowExpand({ dataSourceCopy, rowKeyG
818
824
 
819
825
  const { toggleTreeNode, setTreeExpand, flatTreeData } = useTree({ props, dataSourceCopy, rowKeyGen, emits });
820
826
 
827
+ const { hiddenCellMap, mergeCellsWrapper, hoverMergedCells, updateHoverMergedCells, activeMergedCells, updateActiveMergedCells } = useMergeCells({
828
+ props,
829
+ tableHeaderLast,
830
+ rowKeyGen,
831
+ colKeyGen,
832
+ virtual_dataSourcePart,
833
+ });
834
+
821
835
  watch(
822
836
  () => props.columns,
823
837
  () => {
@@ -993,10 +1007,10 @@ function dealColumns() {
993
1007
  const rowSpan = col.children ? 1 : maxDeep - depth + 1;
994
1008
  const colSpan = colChildrenLen;
995
1009
  if (rowSpan > 1) {
996
- col.rowSpan = rowSpan;
1010
+ col.__R_SP__ = rowSpan;
997
1011
  }
998
1012
  if (colSpan > 1) {
999
- col.colSpan = colSpan;
1013
+ col.__C_SP__ = colSpan;
1000
1014
  }
1001
1015
 
1002
1016
  allChildrenLen += colChildrenLen;
@@ -1154,9 +1168,11 @@ function onRowClick(e: MouseEvent, row: DT, rowIndex: number) {
1154
1168
  // 点击同一行,取消当前选中行。
1155
1169
  currentRow.value = void 0;
1156
1170
  currentRowKey.value = void 0;
1171
+ updateActiveMergedCells(true);
1157
1172
  } else {
1158
1173
  currentRow.value = row;
1159
1174
  currentRowKey.value = rowKeyGen(row);
1175
+ updateActiveMergedCells();
1160
1176
  }
1161
1177
  emits('current-change', e, row, { select: !isCurrentRow });
1162
1178
  }
@@ -1337,7 +1353,24 @@ function onTableScroll(e: Event) {
1337
1353
  function onTrMouseOver(_e: MouseEvent, row: DT) {
1338
1354
  if (currentHoverRow === row) return;
1339
1355
  currentHoverRow = row;
1340
- currentHoverRowKey.value = rowKeyGen(row);
1356
+ const rowKey = rowKeyGen(row);
1357
+ if (props.showTrHoverClass) {
1358
+ currentHoverRowKey.value = rowKey;
1359
+ }
1360
+ if (props.rowHover) {
1361
+ updateHoverMergedCells(rowKey);
1362
+ }
1363
+ }
1364
+
1365
+ function onTrMouseLeave(e: MouseEvent) {
1366
+ if ((e.target as HTMLTableRowElement).tagName !== 'TR') return;
1367
+ currentHoverRow = null;
1368
+ if (props.showTrHoverClass) {
1369
+ currentHoverRowKey.value = null;
1370
+ }
1371
+ if (props.rowHover) {
1372
+ updateHoverMergedCells(void 0);
1373
+ }
1341
1374
  }
1342
1375
 
1343
1376
  /**
@@ -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
- &::before {
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}--${colKeyValue}"]`);
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: (row: any) => UniqKey;
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
- () => onlyDragScroll.value,
26
- v => {
27
- if (v) {
28
- addEventListener();
29
- } else {
30
- removeEventListener();
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
- if (!isMouseDown) return;
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 };