stk-table-vue 0.6.4 → 0.6.6
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 +11 -3
- package/lib/src/StkTable/StkTable.vue.d.ts +12 -7
- package/lib/src/StkTable/index.d.ts +1 -1
- package/lib/src/StkTable/types/index.d.ts +4 -0
- package/lib/src/StkTable/useColResize.d.ts +1 -0
- package/lib/src/StkTable/useFixedCol.d.ts +2 -2
- package/lib/src/StkTable/utils/index.d.ts +10 -2
- package/lib/stk-table-vue.js +97 -72
- package/lib/style.css +14 -12
- package/package.json +9 -5
- package/src/StkTable/StkTable.vue +15 -8
- package/src/StkTable/index.ts +1 -1
- package/src/StkTable/style.less +18 -13
- package/src/StkTable/types/index.ts +5 -0
- package/src/StkTable/useColResize.ts +11 -2
- package/src/StkTable/useFixedCol.ts +46 -40
- package/src/StkTable/useHighlight.ts +3 -3
- package/src/StkTable/useThDrag.ts +2 -2
- package/src/StkTable/useVirtualScroll.ts +44 -18
- package/src/StkTable/utils/index.ts +28 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stk-table-vue",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"description": "Simple realtime virtual table for vue3 and vue2.7",
|
|
5
5
|
"main": "./lib/stk-table-vue.js",
|
|
6
6
|
"types": "./lib/src/StkTable/index.d.ts",
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
"dev": "vite",
|
|
14
14
|
"build": "vite build",
|
|
15
15
|
"test": "vitest",
|
|
16
|
-
"docs:dev": "vitepress dev docs",
|
|
17
|
-
"docs:build": "vitepress build docs",
|
|
18
|
-
"docs:preview": "vitepress preview docs"
|
|
16
|
+
"docs:dev": "vitepress dev docs-src",
|
|
17
|
+
"docs:build": "vitepress build docs-src",
|
|
18
|
+
"docs:preview": "vitepress preview docs-src",
|
|
19
|
+
"docs:update": "cp -rf ./docs-src/.vitepress/dist/* ./docs"
|
|
19
20
|
},
|
|
20
21
|
"keywords": [
|
|
21
22
|
"virtual table",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"license": "MIT",
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@types/d3-interpolate": "^3.0.4",
|
|
44
|
+
"@types/mockjs": "^1.0.10",
|
|
43
45
|
"@types/node": "^20.12.10",
|
|
44
46
|
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
45
47
|
"@typescript-eslint/parser": "^7.7.0",
|
|
@@ -52,6 +54,8 @@
|
|
|
52
54
|
"eslint-plugin-vue": "^9.25.0",
|
|
53
55
|
"happy-dom": "^12.10.3",
|
|
54
56
|
"less": "^4.2.0",
|
|
57
|
+
"mitt": "^3.0.1",
|
|
58
|
+
"mockjs": "^1.1.0",
|
|
55
59
|
"postcss": "^8.4.47",
|
|
56
60
|
"postcss-discard-comments": "^6.0.2",
|
|
57
61
|
"postcss-preset-env": "^9.5.11",
|
|
@@ -60,7 +64,7 @@
|
|
|
60
64
|
"vite": "^5.4.10",
|
|
61
65
|
"vite-plugin-dts": "^4.3.0",
|
|
62
66
|
"vitepress": "^1.5.0",
|
|
63
|
-
"vitepress-demo-plugin": "^1.
|
|
67
|
+
"vitepress-demo-plugin": "^1.2.2",
|
|
64
68
|
"vitest": "^2.1.3",
|
|
65
69
|
"vue": "^3.5.12",
|
|
66
70
|
"vue-eslint-parser": "^9.4.2"
|
|
@@ -102,11 +102,11 @@
|
|
|
102
102
|
</span>
|
|
103
103
|
<!-- 列宽拖动handler -->
|
|
104
104
|
<div
|
|
105
|
-
v-if="
|
|
105
|
+
v-if="colResizeOn(col) && colIndex > 0"
|
|
106
106
|
class="table-header-resizer left"
|
|
107
107
|
@mousedown="e => onThResizeMouseDown(e, col, true)"
|
|
108
108
|
></div>
|
|
109
|
-
<div v-if="
|
|
109
|
+
<div v-if="colResizeOn(col)" class="table-header-resizer right" @mousedown="e => onThResizeMouseDown(e, col)"></div>
|
|
110
110
|
</div>
|
|
111
111
|
</th>
|
|
112
112
|
<!-- 这个th用于横向虚拟滚动表格右边距 width、maxWidth 用于兼容低版本浏览器-->
|
|
@@ -139,7 +139,8 @@
|
|
|
139
139
|
'expanded-row': row && row.__EXPANDED_ROW__,
|
|
140
140
|
}"
|
|
141
141
|
:style="{
|
|
142
|
-
'--row-height':
|
|
142
|
+
'--row-height':
|
|
143
|
+
row && row.__EXPANDED_ROW__ && props.virtual && props.expandConfig?.height && props.expandConfig?.height + 'px',
|
|
143
144
|
}"
|
|
144
145
|
@click="e => onRowClick(e, row)"
|
|
145
146
|
@dblclick="e => onRowDblclick(e, row)"
|
|
@@ -226,6 +227,7 @@
|
|
|
226
227
|
<div v-if="(!dataSourceCopy || !dataSourceCopy.length) && showNoData" class="stk-table-no-data" :class="{ 'no-data-full': noDataFull }">
|
|
227
228
|
<slot name="empty">暂无数据</slot>
|
|
228
229
|
</div>
|
|
230
|
+
<slot name="customBottom"></slot>
|
|
229
231
|
</div>
|
|
230
232
|
</template>
|
|
231
233
|
|
|
@@ -253,6 +255,7 @@ import {
|
|
|
253
255
|
StkTableColumn,
|
|
254
256
|
TagType,
|
|
255
257
|
UniqKeyProp,
|
|
258
|
+
ColResizableConfig,
|
|
256
259
|
} from './types/index';
|
|
257
260
|
import { useAutoResize } from './useAutoResize';
|
|
258
261
|
import { useColResize } from './useColResize';
|
|
@@ -354,7 +357,7 @@ const props = withDefaults(
|
|
|
354
357
|
* 列宽拖动时,每一列都必须要有width,且minWidth/maxWidth不生效。table width会变为"fit-content"。
|
|
355
358
|
* - 会自动更新props.columns中的with属性
|
|
356
359
|
*/
|
|
357
|
-
colResizable?: boolean
|
|
360
|
+
colResizable?: boolean | ColResizableConfig<DT>;
|
|
358
361
|
/** 可拖动至最小的列宽 */
|
|
359
362
|
colMinWidth?: number;
|
|
360
363
|
/**
|
|
@@ -385,7 +388,7 @@ const props = withDefaults(
|
|
|
385
388
|
seqConfig?: SeqConfig;
|
|
386
389
|
/** 展开行配置 */
|
|
387
390
|
expandConfig?: ExpandConfig;
|
|
388
|
-
/**
|
|
391
|
+
/** 行拖动配置 */
|
|
389
392
|
dragRowConfig?: DragRowConfig;
|
|
390
393
|
/**
|
|
391
394
|
* 固定头,固定列实现方式。(非响应式)
|
|
@@ -747,10 +750,10 @@ const { fixedCols, fixedColClassMap, updateFixedShadow } = useFixedCol({
|
|
|
747
750
|
getFixedColPosition,
|
|
748
751
|
tableContainerRef,
|
|
749
752
|
tableHeaders,
|
|
750
|
-
|
|
753
|
+
tableHeadersForCalc,
|
|
751
754
|
});
|
|
752
755
|
|
|
753
|
-
const { isColResizing, onThResizeMouseDown } = useColResize({
|
|
756
|
+
const { isColResizing, onThResizeMouseDown, colResizeOn } = useColResize({
|
|
754
757
|
props,
|
|
755
758
|
emits,
|
|
756
759
|
colKeyGen,
|
|
@@ -1286,6 +1289,7 @@ function setSelectedCell(row?: DT, col?: StkTableColumn<DT>, option = { silent:
|
|
|
1286
1289
|
* @param option.sort 是否触发排序-默认true
|
|
1287
1290
|
* @param option.silent 是否禁止触发回调-默认true
|
|
1288
1291
|
* @param option.force 是否触发排序-默认true
|
|
1292
|
+
* @return 表格数据
|
|
1289
1293
|
*/
|
|
1290
1294
|
function setSorter(colKey: string, order: Order, option: { sortOption?: SortOption<DT>; force?: boolean; silent?: boolean; sort?: boolean } = {}) {
|
|
1291
1295
|
const newOption = { silent: true, sortOption: null, sort: true, ...option };
|
|
@@ -1323,7 +1327,10 @@ function getTableData() {
|
|
|
1323
1327
|
return toRaw(dataSourceCopy.value);
|
|
1324
1328
|
}
|
|
1325
1329
|
|
|
1326
|
-
/**
|
|
1330
|
+
/**
|
|
1331
|
+
* get current sort info
|
|
1332
|
+
* @return {{key:string,order:Order}[]}
|
|
1333
|
+
*/
|
|
1327
1334
|
function getSortColumns() {
|
|
1328
1335
|
const sortOrder = sortSwitchOrder[sortOrderIndex.value];
|
|
1329
1336
|
if (!sortOrder) return [];
|
package/src/StkTable/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default as StkTable } from './StkTable.vue';
|
|
2
|
-
export { tableSort, insertToOrderedArray, strCompare } from './utils';
|
|
2
|
+
export { tableSort, insertToOrderedArray, strCompare, binarySearch } from './utils';
|
|
3
3
|
export type { StkTableColumn } from './types/index';
|
|
4
4
|
import './style.less';
|
package/src/StkTable/style.less
CHANGED
|
@@ -50,9 +50,6 @@
|
|
|
50
50
|
flex-direction: column;
|
|
51
51
|
box-sizing: border-box;
|
|
52
52
|
|
|
53
|
-
/* 下面border用于表格内容不满高度时,绘制表格边界线 */
|
|
54
|
-
background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
|
|
55
|
-
|
|
56
53
|
/**深色模式 */
|
|
57
54
|
&.dark {
|
|
58
55
|
--th-bgc: #202029;
|
|
@@ -85,17 +82,20 @@
|
|
|
85
82
|
/* ⭐这里加background-color会导致表格出滚动白屏*/
|
|
86
83
|
color: #d1d1e0;
|
|
87
84
|
}
|
|
85
|
+
|
|
88
86
|
|
|
89
87
|
&.headless {
|
|
90
|
-
border
|
|
91
|
-
|
|
88
|
+
&.border {
|
|
89
|
+
border-top: 1px solid var(--border-color);
|
|
90
|
+
background-image: var(--bg-border-right), var(--bg-border-bottom);
|
|
91
|
+
}
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/* 调整列宽的话,表格宽度应当自适应 */
|
|
95
95
|
&.col-resizable {
|
|
96
96
|
.stk-table-main {
|
|
97
|
-
width: fit-content
|
|
98
|
-
min-width: min-content
|
|
97
|
+
width: fit-content;
|
|
98
|
+
min-width: min-content;
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -115,6 +115,8 @@
|
|
|
115
115
|
* - sticky 定位方案需要占用位置。高度为0。
|
|
116
116
|
*/
|
|
117
117
|
border-left: 1px solid var(--border-color);
|
|
118
|
+
/* 下面border用于表格内容不满高度时,绘制表格边界线 */
|
|
119
|
+
background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
|
|
118
120
|
|
|
119
121
|
th,
|
|
120
122
|
td {
|
|
@@ -155,17 +157,18 @@
|
|
|
155
157
|
background-color: var(--stripe-bgc);
|
|
156
158
|
}
|
|
157
159
|
|
|
158
|
-
&.row-hover .stk-tbody-main tr:hover {
|
|
160
|
+
&.row-hover .stk-table-main .stk-tbody-main tr:hover {
|
|
159
161
|
background-color: var(--tr-hover-bgc);
|
|
160
162
|
}
|
|
161
163
|
|
|
162
|
-
&.row-active .stk-tbody-main tr.active {
|
|
164
|
+
&.row-active .stk-table-main .stk-tbody-main tr.active {
|
|
163
165
|
background-color: var(--tr-active-bgc);
|
|
164
166
|
}
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
|
|
168
|
-
|
|
170
|
+
/** more weight for custom row background*/
|
|
171
|
+
&.row-hover .stk-table-main .stk-tbody-main tr:hover {
|
|
169
172
|
background-color: var(--tr-hover-bgc);
|
|
170
173
|
}
|
|
171
174
|
|
|
@@ -213,6 +216,10 @@
|
|
|
213
216
|
.table-header-cell-wrapper {
|
|
214
217
|
overflow: hidden;
|
|
215
218
|
max-height: calc(var(--header-row-height) * var(--row-span, 1));
|
|
219
|
+
|
|
220
|
+
.table-header-title {
|
|
221
|
+
max-height: inherit;
|
|
222
|
+
}
|
|
216
223
|
}
|
|
217
224
|
|
|
218
225
|
tbody td {
|
|
@@ -379,8 +386,7 @@
|
|
|
379
386
|
.expand-cell {
|
|
380
387
|
cursor: pointer;
|
|
381
388
|
|
|
382
|
-
|
|
383
|
-
&.expanded-cell-wrapper {
|
|
389
|
+
.expanded-cell-wrapper {
|
|
384
390
|
&::before {
|
|
385
391
|
content: '';
|
|
386
392
|
display: inline-block;
|
|
@@ -397,7 +403,6 @@
|
|
|
397
403
|
margin-left: var(--cell-padding-x)
|
|
398
404
|
}
|
|
399
405
|
}
|
|
400
|
-
}
|
|
401
406
|
|
|
402
407
|
&.expanded {
|
|
403
408
|
.table-cell-wrapper::before {
|
|
@@ -200,6 +200,7 @@ export type SeqConfig = {
|
|
|
200
200
|
|
|
201
201
|
/** Configuration options for the expand column */
|
|
202
202
|
export type ExpandConfig = {
|
|
203
|
+
/** worked in virtual mode */
|
|
203
204
|
height?: number;
|
|
204
205
|
};
|
|
205
206
|
|
|
@@ -232,3 +233,7 @@ export type AutoRowHeightConfig<DT> = {
|
|
|
232
233
|
/** Estimated row height */
|
|
233
234
|
expectedHeight?: number | ((row: DT, index: number) => number);
|
|
234
235
|
};
|
|
236
|
+
|
|
237
|
+
export type ColResizableConfig<DT extends Record<string, any>> = {
|
|
238
|
+
disabled: (col: StkTableColumn<DT>) => boolean;
|
|
239
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComputedRef, Ref, ShallowRef, onBeforeUnmount, onMounted, ref } from 'vue';
|
|
1
|
+
import { ComputedRef, Ref, ShallowRef, computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
|
2
2
|
import { StkTableColumn, UniqKey } from './types';
|
|
3
3
|
import { getCalculatedColWidth } from './utils/constRefUtils';
|
|
4
4
|
|
|
@@ -47,6 +47,14 @@ export function useColResize<DT extends Record<string, any>>({
|
|
|
47
47
|
revertMoveX: false,
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
+
/** 是否可拖动 */
|
|
51
|
+
const colResizeOn = computed(() => {
|
|
52
|
+
if (Object.prototype.toString.call(props.colResizable) === '[object Object]') {
|
|
53
|
+
return (col: StkTableColumn<DT>) => !props.colResizable.disabled(col);
|
|
54
|
+
}
|
|
55
|
+
return () => props.colResizable;
|
|
56
|
+
});
|
|
57
|
+
|
|
50
58
|
onMounted(() => {
|
|
51
59
|
initColResizeEvent();
|
|
52
60
|
});
|
|
@@ -93,7 +101,7 @@ export function useColResize<DT extends Record<string, any>>({
|
|
|
93
101
|
// 对于固定右侧的列,拖动左侧的把,需要反向计算
|
|
94
102
|
revertMoveX = true;
|
|
95
103
|
} else {
|
|
96
|
-
//
|
|
104
|
+
// 取上一列
|
|
97
105
|
if (colIndex - 1 >= 0) {
|
|
98
106
|
col = tableHeaderLastValue[colIndex - 1];
|
|
99
107
|
}
|
|
@@ -198,6 +206,7 @@ export function useColResize<DT extends Record<string, any>>({
|
|
|
198
206
|
}
|
|
199
207
|
|
|
200
208
|
return {
|
|
209
|
+
colResizeOn,
|
|
201
210
|
isColResizing,
|
|
202
211
|
onThResizeMouseDown,
|
|
203
212
|
};
|
|
@@ -8,7 +8,7 @@ type Params<T extends Record<string, any>> = {
|
|
|
8
8
|
colKeyGen: ComputedRef<(col: StkTableColumn<T>) => UniqKey>;
|
|
9
9
|
getFixedColPosition: ComputedRef<(col: StkTableColumn<T>) => number>;
|
|
10
10
|
tableHeaders: ShallowRef<StkTableColumn<T>[][]>;
|
|
11
|
-
|
|
11
|
+
tableHeadersForCalc: ShallowRef<StkTableColumn<T>[][]>;
|
|
12
12
|
tableContainerRef: Ref<HTMLDivElement | undefined>;
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -21,7 +21,7 @@ export function useFixedCol<DT extends Record<string, any>>({
|
|
|
21
21
|
colKeyGen,
|
|
22
22
|
getFixedColPosition,
|
|
23
23
|
tableHeaders,
|
|
24
|
-
|
|
24
|
+
tableHeadersForCalc,
|
|
25
25
|
tableContainerRef,
|
|
26
26
|
}: Params<DT>) {
|
|
27
27
|
/** 保存需要出现阴影的列 */
|
|
@@ -56,27 +56,26 @@ export function useFixedCol<DT extends Record<string, any>>({
|
|
|
56
56
|
* @param type 1-shadow(阴影) 2-active(被固定的列)
|
|
57
57
|
*
|
|
58
58
|
*/
|
|
59
|
-
function getColAndParentCols(col: StkTableColumn<DT> | null, type: 1 | 2 = 1) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
59
|
+
// function getColAndParentCols(col: StkTableColumn<DT> | null, type: 1 | 2 = 1) {
|
|
60
|
+
// if (!col) return [];
|
|
61
|
+
// const colsTemp: StkTableColumn<DT>[] = [];
|
|
62
|
+
// let node: any = { __PARENT__: col };
|
|
63
|
+
// while ((node = node.__PARENT__)) {
|
|
64
|
+
// if (type === 1 && node.fixed) {
|
|
65
|
+
// // shadow
|
|
66
|
+
// colsTemp.push(node);
|
|
67
|
+
// }
|
|
68
|
+
// if (type === 2) {
|
|
69
|
+
// // active
|
|
70
|
+
// colsTemp.push(node);
|
|
71
|
+
// }
|
|
72
|
+
// }
|
|
73
|
+
// return colsTemp;
|
|
74
|
+
// }
|
|
75
75
|
|
|
76
76
|
/** 滚动条变化时,更新需要展示阴影的列 */
|
|
77
77
|
function updateFixedShadow(virtualScrollX?: Ref<VirtualScrollXStore>) {
|
|
78
78
|
const fixedColsTemp: StkTableColumn<DT>[] = [];
|
|
79
|
-
const fixedShadowColsTemp: (StkTableColumn<DT> | null)[] = [];
|
|
80
79
|
let clientWidth, /* scrollWidth, */ scrollLeft;
|
|
81
80
|
|
|
82
81
|
if (virtualScrollX?.value) {
|
|
@@ -95,31 +94,38 @@ export function useFixedCol<DT extends Record<string, any>>({
|
|
|
95
94
|
* 根据横向滚动位置,计算出哪个列需要展示阴影
|
|
96
95
|
*****/
|
|
97
96
|
/** 左侧需要展示阴影的列 */
|
|
98
|
-
|
|
97
|
+
const leftShadowCol: StkTableColumn<DT>[] = [];
|
|
99
98
|
/** 右侧展示阴影的列 */
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
99
|
+
const rightShadowCol: StkTableColumn<DT>[] = [];
|
|
100
|
+
tableHeadersForCalc.value.forEach((row, level) => {
|
|
101
|
+
/**
|
|
102
|
+
* 左侧第n个fixed:left 计算要加上前面所有left 的列宽。
|
|
103
|
+
*/
|
|
104
|
+
let left = 0;
|
|
105
|
+
row.forEach(col => {
|
|
106
|
+
const position = getFixedColPosition.value(col);
|
|
107
|
+
const isFixedLeft = col.fixed === 'left';
|
|
108
|
+
const isFixedRight = col.fixed === 'right';
|
|
109
|
+
|
|
110
|
+
if (isFixedLeft && position + scrollLeft > left) {
|
|
111
|
+
fixedColsTemp.push(col);
|
|
112
|
+
leftShadowCol[level] = col;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
left += getCalculatedColWidth(col);
|
|
116
|
+
|
|
117
|
+
if (isFixedRight && scrollLeft + clientWidth - left < position) {
|
|
118
|
+
fixedColsTemp.push(col);
|
|
119
|
+
// 右固定列阴影,只要第一列
|
|
120
|
+
if (!rightShadowCol[level]) {
|
|
121
|
+
rightShadowCol[level] = col;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
118
125
|
});
|
|
119
126
|
|
|
120
127
|
if (props.fixedColShadow) {
|
|
121
|
-
|
|
122
|
-
fixedShadowCols.value = (fixedShadowColsTemp as (StkTableColumn<DT> | null)[]).filter(Boolean) as StkTableColumn<DT>[];
|
|
128
|
+
fixedShadowCols.value = [...leftShadowCol, ...rightShadowCol].filter(Boolean) as StkTableColumn<DT>[];
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
fixedCols.value = fixedColsTemp;
|
|
@@ -89,7 +89,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
89
89
|
const { ts, duration } = store;
|
|
90
90
|
const timeOffset = nowTs - ts;
|
|
91
91
|
if (nowTs - ts < duration) {
|
|
92
|
-
|
|
92
|
+
updateRowAnimation(rowKeyValue, store, timeOffset);
|
|
93
93
|
} else {
|
|
94
94
|
highlightDimRowsAnimation.delete(rowKeyValue);
|
|
95
95
|
}
|
|
@@ -197,7 +197,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
197
197
|
const rowKeyValue = rowKeyValues[i];
|
|
198
198
|
const store: HighlightDimRowStore = { ts: nowTs, visible: false, keyframe, duration };
|
|
199
199
|
highlightDimRowsAnimation.set(rowKeyValue, store);
|
|
200
|
-
|
|
200
|
+
updateRowAnimation(rowKeyValue, store, 0);
|
|
201
201
|
}
|
|
202
202
|
calcRowHighlightLoop();
|
|
203
203
|
} else {
|
|
@@ -279,7 +279,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
|
|
|
279
279
|
* @param store highlightDimRowStore 的引用对象
|
|
280
280
|
* @param timeOffset 距动画开始经过的时长
|
|
281
281
|
*/
|
|
282
|
-
function
|
|
282
|
+
function updateRowAnimation(rowKeyValue: UniqKey, store: HighlightDimRowStore, timeOffset: number) {
|
|
283
283
|
const rowEl = document.getElementById(stkTableId + '-' + String(rowKeyValue));
|
|
284
284
|
const { visible, keyframe, duration: initialDuration } = store;
|
|
285
285
|
if (!rowEl) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { computed, ComputedRef } from 'vue';
|
|
2
2
|
import { StkTableColumn, UniqKey } from './types';
|
|
3
|
+
import { isEmptyValue } from './utils';
|
|
3
4
|
|
|
4
5
|
type Params<T extends Record<string, any>> = {
|
|
5
6
|
props: any;
|
|
@@ -57,7 +58,6 @@ export function useThDrag<DT extends Record<string, any>>({ props, emits, colKey
|
|
|
57
58
|
const th = findParentTH(e);
|
|
58
59
|
if (!th) return;
|
|
59
60
|
const dragStartKey = e.dataTransfer?.getData('text');
|
|
60
|
-
|
|
61
61
|
if (dragStartKey !== th.dataset.colKey) {
|
|
62
62
|
handleColOrderChange(dragStartKey, th.dataset.colKey);
|
|
63
63
|
}
|
|
@@ -66,7 +66,7 @@ export function useThDrag<DT extends Record<string, any>>({ props, emits, colKey
|
|
|
66
66
|
|
|
67
67
|
/** 列拖动交换顺序 */
|
|
68
68
|
function handleColOrderChange(dragStartKey: string | undefined, dragEndKey: string | undefined) {
|
|
69
|
-
if (
|
|
69
|
+
if (isEmptyValue(dragStartKey) || isEmptyValue(dragEndKey)) return;
|
|
70
70
|
|
|
71
71
|
if (dragConfig.value.mode !== 'none') {
|
|
72
72
|
const columns = [...props.columns];
|
|
@@ -79,6 +79,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
79
79
|
scrollHeight: 0,
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
+
// TODO: init pageSize
|
|
83
|
+
|
|
82
84
|
const virtualScrollX = ref<VirtualScrollXStore>({
|
|
83
85
|
containerWidth: 0,
|
|
84
86
|
scrollWidth: 0,
|
|
@@ -88,6 +90,10 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
88
90
|
scrollLeft: 0,
|
|
89
91
|
});
|
|
90
92
|
|
|
93
|
+
const hasExpandCol = computed(() => {
|
|
94
|
+
return tableHeaderLast.value.some(col => col.type === 'expand');
|
|
95
|
+
});
|
|
96
|
+
|
|
91
97
|
/** 是否虚拟滚动标志 */
|
|
92
98
|
const virtual_on = computed(() => {
|
|
93
99
|
return props.virtual && dataSourceCopy.value.length > virtualScroll.value.pageSize * 2;
|
|
@@ -198,10 +204,9 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
198
204
|
const headerToBodyRowHeightCount = Math.floor(headerHeight / rowHeight);
|
|
199
205
|
pageSize -= headerToBodyRowHeightCount; //减去表头行数
|
|
200
206
|
}
|
|
201
|
-
/** 最大的scrollTop */
|
|
202
207
|
const maxScrollTop = dataSourceCopy.value.length * rowHeight + tableHeaderHeight.value - containerHeight;
|
|
203
208
|
if (scrollTop > maxScrollTop) {
|
|
204
|
-
/**
|
|
209
|
+
/** fix: 滚动条不在顶部时,表格数据变少,导致滚动条位置有误 */
|
|
205
210
|
scrollTop = maxScrollTop;
|
|
206
211
|
}
|
|
207
212
|
Object.assign(virtualScroll.value, { containerHeight, pageSize, scrollHeight });
|
|
@@ -237,7 +242,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
237
242
|
let expectedHeight;
|
|
238
243
|
if (storedHeight) {
|
|
239
244
|
return storedHeight;
|
|
240
|
-
}
|
|
245
|
+
}
|
|
246
|
+
if ((expectedHeight = props.autoRowHeight?.expectedHeight)) {
|
|
241
247
|
if (typeof expectedHeight === 'function') {
|
|
242
248
|
return expectedHeight(row);
|
|
243
249
|
} else {
|
|
@@ -247,6 +253,18 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
247
253
|
return props.rowHeight || DEFAULT_ROW_HEIGHT;
|
|
248
254
|
};
|
|
249
255
|
|
|
256
|
+
const createGetRowHeightFn: () => (row: DT) => number = () => {
|
|
257
|
+
if (props.autoRowHeight) {
|
|
258
|
+
return (row: DT) => getAutoRowHeight(row);
|
|
259
|
+
}
|
|
260
|
+
if (hasExpandCol.value) {
|
|
261
|
+
const { rowHeight } = virtualScroll.value;
|
|
262
|
+
const expandedRowHeight: number = props.expandConfig?.height || rowHeight;
|
|
263
|
+
return (row: DT) => (row.__EXPANDED_ROW__ ? expandedRowHeight : rowHeight);
|
|
264
|
+
}
|
|
265
|
+
return () => props.rowHeight || (DEFAULT_ROW_HEIGHT as number);
|
|
266
|
+
};
|
|
267
|
+
|
|
250
268
|
/** 通过滚动条位置,计算虚拟滚动的参数 */
|
|
251
269
|
function updateVirtualScrollY(sTop = 0) {
|
|
252
270
|
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex, endIndex: oldEndIndex } = virtualScroll.value;
|
|
@@ -257,24 +275,32 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
257
275
|
if (!virtual_on.value) {
|
|
258
276
|
return;
|
|
259
277
|
}
|
|
278
|
+
|
|
279
|
+
const dataSourceCopyTemp = dataSourceCopy.value;
|
|
260
280
|
const { autoRowHeight, stripe, optimizeVue2Scroll } = props;
|
|
261
281
|
|
|
262
282
|
let startIndex = 0;
|
|
263
|
-
|
|
264
283
|
let autoRowHeightTop = 0;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
284
|
+
let getRowHeight: ReturnType<typeof createGetRowHeightFn> | null = null;
|
|
285
|
+
const dataLength = dataSourceCopyTemp.length;
|
|
286
|
+
|
|
287
|
+
if (autoRowHeight || hasExpandCol.value) {
|
|
288
|
+
if (autoRowHeight) {
|
|
289
|
+
trRef.value?.forEach(tr => {
|
|
290
|
+
const { rowKey } = tr.dataset;
|
|
291
|
+
if (!rowKey || autoRowHeightMap.has(rowKey)) return;
|
|
292
|
+
autoRowHeightMap.set(rowKey, tr.offsetHeight);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
getRowHeight = createGetRowHeightFn();
|
|
297
|
+
|
|
298
|
+
for (let i = 0; i < dataLength; i++) {
|
|
299
|
+
const height = getRowHeight(dataSourceCopyTemp[i]);
|
|
274
300
|
autoRowHeightTop += height;
|
|
275
301
|
if (autoRowHeightTop >= sTop) {
|
|
276
302
|
startIndex = i;
|
|
277
|
-
autoRowHeightTop
|
|
303
|
+
autoRowHeightTop -= height;
|
|
278
304
|
break;
|
|
279
305
|
}
|
|
280
306
|
}
|
|
@@ -287,8 +313,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
287
313
|
if (stripe && startIndex > 0 && startIndex % 2) {
|
|
288
314
|
// 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
|
|
289
315
|
startIndex -= 1; // 奇数-1变成偶数
|
|
290
|
-
if (autoRowHeight) {
|
|
291
|
-
const height =
|
|
316
|
+
if (autoRowHeight || hasExpandCol.value) {
|
|
317
|
+
const height = getRowHeight!(dataSourceCopyTemp[startIndex]);
|
|
292
318
|
autoRowHeightTop -= height;
|
|
293
319
|
}
|
|
294
320
|
}
|
|
@@ -296,7 +322,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
296
322
|
startIndex = Math.max(0, startIndex);
|
|
297
323
|
|
|
298
324
|
// 溢出修正
|
|
299
|
-
endIndex = Math.min(endIndex,
|
|
325
|
+
endIndex = Math.min(endIndex, dataLength);
|
|
300
326
|
|
|
301
327
|
if (startIndex >= endIndex) {
|
|
302
328
|
// 兜底,不一定会执行到这里
|
|
@@ -308,7 +334,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
308
334
|
}
|
|
309
335
|
|
|
310
336
|
let offsetTop = 0;
|
|
311
|
-
if (autoRowHeight) {
|
|
337
|
+
if (autoRowHeight || hasExpandCol.value) {
|
|
312
338
|
offsetTop = autoRowHeightTop;
|
|
313
339
|
} else {
|
|
314
340
|
if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
|