stk-table-vue 0.7.1 → 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.
@@ -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;
@@ -40,18 +40,6 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
40
40
  const highlightSteps = computed(() => (highlightFrequency.value ? Math.round(highlightDuration.value / highlightFrequency.value) : null));
41
41
  /** 高亮开始 */
42
42
  const highlightFrom = computed(() => highlightColor[props.theme as 'light' | 'dark'].from);
43
- /** 高亮结束 */
44
- // const highlightTo = computed(() => highlightColor[props.theme as 'light' | 'dark'].to);
45
- // const highlightInter = computed(() => interpolateRgb(highlightFrom.value, highlightTo.value));
46
-
47
- /**
48
- * 存放高亮行的状态-使用js计算颜色
49
- * @key 行唯一键
50
- * @value 记录高亮开始时间
51
- */
52
- // const highlightDimRowsJs = new Map<UniqKey, number>();
53
- /** 是否正在计算高亮行的循环-使用js计算颜色 */
54
- // const calcHighlightDimLoopJs = false;
55
43
 
56
44
  /**
57
45
  * 存放高亮行的状态-使用animation api实现
@@ -85,7 +73,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
85
73
  const recursion = () => {
86
74
  window.requestAnimationFrame(
87
75
  () => {
88
- const nowTs = Date.now();
76
+ const nowTs = performance.now();
89
77
  highlightDimRowsAnimation.forEach((store, rowKeyValue) => {
90
78
  const { ts, duration } = store;
91
79
  const timeOffset = nowTs - ts;
@@ -110,59 +98,24 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
110
98
  recursion();
111
99
  }
112
100
 
113
- /**
114
- * js计算高亮渐暗颜色的循环
115
- */
116
- // function calcRowHighlightLoopJs() {
117
- // if (calcHighlightDimLoopJs) return;
118
- // calcHighlightDimLoopJs = true;
119
- // // js计算gradient
120
- // const recursion = () => {
121
- // window.setTimeout(() => {
122
- // const nowTs = Date.now();
123
- // highlightDimRowsJs.forEach((highlightStart, rowKeyValue) => {
124
- // /** 经过的时间 ÷ 高亮持续时间 计算出 颜色过渡进度 (0-1) */
125
- // const progress = (nowTs - highlightStart) / highlightDuration;
126
- // let bgc = '';
127
- // if (0 <= progress && progress <= 1) {
128
- // bgc = highlightInter.value(progress);
129
- // } else {
130
- // highlightDimRowsJs.delete(rowKeyValue);
131
- // }
132
- // updateRowBgcJs(rowKeyValue, bgc);
133
- // });
134
-
135
- // if (highlightDimRowsJs.size > 0) {
136
- // // 还有高亮的行,则下一次循环
137
- // recursion();
138
- // } else {
139
- // // 没有则停止循环
140
- // calcHighlightDimLoopJs = false;
141
- // highlightDimRowsJs.clear(); // TODO: 是否需要 清除
142
- // }
143
- // }, highlightFrequency || HIGHLIGHT_FREQ);
144
- // };
145
- // recursion();
146
- // }
147
-
148
101
  /**
149
102
  * 高亮一个单元格。暂不支持虚拟滚动高亮状态记忆。
150
103
  * @param rowKeyValue 一行的key
151
104
  * @param colKeyValue 列key
152
105
  * @param options.method css-使用css渲染,animation-使用animation api。默认animation;
153
106
  * @param option.className 自定义css动画的class。
154
- * @param option.keyframe Keyframe https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
107
+ * @param option.keyframe 如果自定义keyframe,则 highlightConfig.fps 将会失效。Keyframehttps://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
155
108
  * @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。
156
109
  */
157
110
  function setHighlightDimCell(rowKeyValue: UniqKey, colKeyValue: string, option: HighlightDimCellOption = {}) {
158
- 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
+ if (!cellEl) return;
159
113
  const { className, method, duration, keyframe } = {
160
114
  className: HIGHLIGHT_CELL_CLASS,
161
115
  method: 'animation',
162
116
  ...defaultHighlightDimOption.value,
163
117
  ...option,
164
118
  };
165
- if (!cellEl) return;
166
119
  if (method === 'animation') {
167
120
  cellEl.animate(keyframe, duration);
168
121
  } else {
@@ -175,11 +128,12 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
175
128
  * @param rowKeyValues 行唯一键的数组
176
129
  * @param option.method css-使用css渲染,animation-使用animation api,js-使用js计算颜色。默认animation
177
130
  * @param option.className 自定义css动画的class。
178
- * @param option.keyframe Keyframehttps://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
131
+ * @param option.keyframe 如果自定义keyframe,则 highlightConfig.fps 将会失效。Keyframehttps://developer.mozilla.org/zh-CN/docs/Web/API/Web_Animations_API/Keyframe_Formats
179
132
  * @param option.duration 动画时长。method='css'状态下,用于移除class,如果传入了className则需要与自定义的动画时间一致。。
180
133
  */
181
134
  function setHighlightDimRow(rowKeyValues: UniqKey[], option: HighlightDimRowOption = {}) {
182
135
  if (!Array.isArray(rowKeyValues)) rowKeyValues = [rowKeyValues];
136
+ if (!rowKeyValues.length) return;
183
137
  const { className, method, keyframe, duration } = {
184
138
  className: HIGHLIGHT_ROW_CLASS,
185
139
  method: 'animation',
@@ -187,13 +141,10 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
187
141
  ...option,
188
142
  };
189
143
 
190
- if (method === 'css') {
191
- // -------- use css keyframe
192
- highlightRowsInCssKeyframe(rowKeyValues, className, duration);
193
- } else if (method === 'animation') {
144
+ if (method === 'animation') {
194
145
  if (props.virtual) {
195
146
  // -------- 用animation 接口实现动画
196
- const nowTs = Date.now();
147
+ const nowTs = performance.now();
197
148
  for (let i = 0; i < rowKeyValues.length; i++) {
198
149
  const rowKeyValue = rowKeyValues[i];
199
150
  const store: HighlightDimRowStore = { ts: nowTs, visible: false, keyframe, duration };
@@ -209,17 +160,10 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
209
160
  rowEl.animate(keyframe, duration);
210
161
  }
211
162
  }
163
+ } else {
164
+ // -------- use css keyframe
165
+ highlightRowsInCssKeyframe(rowKeyValues, className, duration);
212
166
  }
213
- // else if (method === 'js') {
214
- // // -------- 用js计算颜色渐变的高亮方案
215
- // const nowTs = Date.now();
216
- // for (let i = 0; i < rowKeyValues.length; i++) {
217
- // const rowKeyValue = rowKeyValues[i];
218
- // highlightDimRowsJs.set(rowKeyValue, nowTs);
219
- // updateRowBgcJs(rowKeyValue, highlightFrom.value);
220
- // }
221
- // calcRowHighlightLoopJs();
222
- // }
223
167
  }
224
168
 
225
169
  /**
@@ -305,13 +249,6 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
305
249
  }
306
250
  }
307
251
 
308
- /** 更新行状态 */
309
- // function updateRowBgcJs(rowKeyValue: UniqKey, color: string) {
310
- // const rowEl = document.getElementById(stkTableId + '-' + String(rowKeyValue));
311
- // if (!rowEl) return;
312
- // rowEl.style.backgroundColor = color;
313
- // }
314
-
315
252
  return {
316
253
  highlightSteps,
317
254
  setHighlightDimRow,
@@ -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
  };
@@ -0,0 +1,79 @@
1
+ import { computed, Ref, ref, onMounted, onUnmounted, watch } from 'vue';
2
+
3
+ type Params = {
4
+ props: any;
5
+ tableContainerRef: Ref<HTMLElement | undefined>;
6
+ };
7
+
8
+ export function useScrollRowByRow({ props, tableContainerRef }: Params) {
9
+ let isMouseDown = false;
10
+ let isAddListeners = false;
11
+ /** record the last scroll bar position */
12
+ let lastScrollTop = 0;
13
+
14
+ /** record is the scroll bar is dragging */
15
+ const isDragScroll = ref(false);
16
+ const onlyDragScroll = computed(() => props.scrollRowByRow === 'scrollbar');
17
+
18
+ /** is ScrollRowByRow active */
19
+ const isSRBRActive = computed(() => {
20
+ if (onlyDragScroll.value) {
21
+ return isDragScroll.value;
22
+ }
23
+ return props.scrollRowByRow;
24
+ });
25
+
26
+ watch(onlyDragScroll, v => {
27
+ if (v) {
28
+ addEventListener();
29
+ } else {
30
+ removeEventListener();
31
+ }
32
+ });
33
+
34
+ onMounted(() => {
35
+ addEventListener();
36
+ });
37
+
38
+ onUnmounted(() => {
39
+ removeEventListener();
40
+ });
41
+
42
+ function addEventListener() {
43
+ if (isAddListeners || !onlyDragScroll.value) return;
44
+ const container = tableContainerRef.value;
45
+ if (!container) return;
46
+ container.addEventListener('mousedown', handleMouseDown);
47
+ container.addEventListener('mouseup', handleMouseUp);
48
+ container.addEventListener('scroll', handleScroll);
49
+ isAddListeners = true;
50
+ }
51
+
52
+ function removeEventListener() {
53
+ const container = tableContainerRef.value;
54
+ if (!container) return;
55
+ container.removeEventListener('mousedown', handleMouseDown);
56
+ container.removeEventListener('mouseup', handleMouseUp);
57
+ container.removeEventListener('scroll', handleScroll);
58
+ isAddListeners = false;
59
+ }
60
+
61
+ function handleMouseDown(e: Event) {
62
+ isMouseDown = true;
63
+ lastScrollTop = (e.target as HTMLElement).scrollTop;
64
+ }
65
+
66
+ function handleMouseUp() {
67
+ isMouseDown = false;
68
+ isDragScroll.value = false;
69
+ lastScrollTop = 0;
70
+ }
71
+
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;
76
+ isDragScroll.value = true;
77
+ }
78
+ return { isSRBRActive, isDragScroll };
79
+ }
@@ -1,17 +1,17 @@
1
- import { computed, ComputedRef } from 'vue';
2
- import { StkTableColumn, UniqKey } from './types';
1
+ import { computed } from 'vue';
2
+ import { ColKeyGen, StkTableColumn } from './types';
3
3
  import { isEmptyValue } from './utils';
4
4
 
5
- type Params<T extends Record<string, any>> = {
5
+ type Params = {
6
6
  props: any;
7
7
  emits: any;
8
- colKeyGen: ComputedRef<(col: StkTableColumn<T>) => UniqKey>;
8
+ colKeyGen: ColKeyGen;
9
9
  };
10
10
  /**
11
11
  * 列顺序拖动
12
12
  * @returns
13
13
  */
14
- export function useThDrag<DT extends Record<string, any>>({ props, emits, colKeyGen }: Params<DT>) {
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<DT>) => dragConfig.value.draggable && !dragConfig.value.disabled(col),
100
+ isHeaderDraggable: (col: StkTableColumn<any>) => dragConfig.value.draggable && !dragConfig.value.disabled(col),
101
101
  };
102
102
  }
@@ -1,10 +1,10 @@
1
1
  import { ShallowRef } from 'vue';
2
- import { PrivateRowDT, TreeConfig, UniqKey } from './types';
2
+ import { PrivateRowDT, RowKeyGen, TreeConfig, UniqKey } from './types';
3
3
 
4
4
  type DT = PrivateRowDT & { children?: DT[] };
5
5
  type Option<DT extends Record<string, any>> = {
6
6
  props: any;
7
- rowKeyGen: (row: any) => UniqKey;
7
+ rowKeyGen: RowKeyGen;
8
8
  dataSourceCopy: ShallowRef<DT[]>;
9
9
  emits: any;
10
10
  };
@@ -1,6 +1,6 @@
1
1
  import { Ref, ShallowRef, computed, ref } from 'vue';
2
2
  import { DEFAULT_ROW_HEIGHT, DEFAULT_TABLE_HEIGHT, DEFAULT_TABLE_WIDTH } from './const';
3
- import { AutoRowHeightConfig, StkTableColumn, UniqKey } from './types';
3
+ import { AutoRowHeightConfig, PrivateStkTableColumn, RowKeyGen, StkTableColumn, UniqKey } from './types';
4
4
  import { getCalculatedColWidth } from './utils/constRefUtils';
5
5
 
6
6
  type Option<DT extends Record<string, any>> = {
@@ -8,9 +8,9 @@ type Option<DT extends Record<string, any>> = {
8
8
  tableContainerRef: Ref<HTMLElement | undefined>;
9
9
  trRef: Ref<HTMLTableRowElement[] | undefined>;
10
10
  dataSourceCopy: ShallowRef<DT[]>;
11
- tableHeaderLast: ShallowRef<StkTableColumn<DT>[]>;
12
- tableHeaders: ShallowRef<StkTableColumn<DT>[][]>;
13
- rowKeyGen: (row: any) => UniqKey;
11
+ tableHeaderLast: ShallowRef<PrivateStkTableColumn<DT>[]>;
12
+ tableHeaders: ShallowRef<PrivateStkTableColumn<DT>[][]>;
13
+ rowKeyGen: RowKeyGen;
14
14
  };
15
15
 
16
16
  /** 暂存纵向虚拟滚动的数据 */
@@ -133,8 +133,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
133
133
  const tableHeaderLastValue = tableHeaderLast.value;
134
134
  if (virtualX_on.value) {
135
135
  // 虚拟横向滚动,固定列要一直保持存在
136
- const leftCols: StkTableColumn<DT>[] = [];
137
- const rightCols: StkTableColumn<DT>[] = [];
136
+ const leftCols: PrivateStkTableColumn<DT>[] = [];
137
+ const rightCols: PrivateStkTableColumn<DT>[] = [];
138
138
  /**
139
139
  * 存在问题:
140
140
  * table columns 从多到少时。比方原来的start=5,end=10,现在start=4,end=8。这时候endIndex就超出数组范围了。
@@ -1,4 +1,5 @@
1
- import { Order, SortConfig, SortOption, SortState, StkTableColumn } from '../types';
1
+ import { CELL_KEY_SEPARATE } from '../const';
2
+ import { Order, SortConfig, SortOption, SortState, StkTableColumn, UniqKey } from '../types';
2
3
 
3
4
  /** 是否空值 */
4
5
  export function isEmptyValue(val: any, isNumber?: boolean) {
@@ -222,3 +223,7 @@ export function getBrowsersVersion(browserName: string) {
222
223
  }
223
224
  return 100;
224
225
  }
226
+
227
+ export function pureCellKeyGen(rowKey: UniqKey, colKey: UniqKey) {
228
+ return rowKey + CELL_KEY_SEPARATE + colKey;
229
+ }