stk-table-vue 0.3.4 → 0.3.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 +10 -7
- package/lib/src/StkTable/StkTable.vue.d.ts +2 -2
- package/lib/src/StkTable/types/index.d.ts +3 -0
- package/lib/src/StkTable/useColResize.d.ts +0 -2
- package/lib/src/StkTable/{utils.d.ts → utils/index.d.ts} +1 -1
- package/lib/src/StkTable/utils/useTriggerRef.d.ts +15 -0
- package/lib/stk-table-vue.js +52 -37
- package/package.json +2 -2
- package/src/StkTable/StkTable.vue +21 -14
- package/src/StkTable/types/index.ts +9 -1
- package/src/StkTable/useColResize.ts +3 -4
- package/src/StkTable/useFixedCol.ts +12 -7
- package/src/StkTable/useVirtualScroll.ts +26 -13
- package/src/StkTable/{utils.ts → utils/index.ts} +2 -2
- package/src/StkTable/utils/useTriggerRef.ts +33 -0
package/README.md
CHANGED
|
@@ -549,16 +549,19 @@ export type SortConfig<T extends Record<string, any>> = {
|
|
|
549
549
|
### 鼠标悬浮表头时,不展示title
|
|
550
550
|
* 将 `StkTableColumn` 中的 `title` 字段置为 "" 空字符串。这样th中就没有title了。
|
|
551
551
|
* 使用 `StkTableColumn` 中的 `customHeaderCell` 属性中,自定义表头渲染。
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
* 指定 `{method:'animation'}` 在虚拟滚动下使用animation api实现动画。好处是动画流畅,且滚动后动画不中断。坏处是不支持帧率配置。
|
|
552
|
+
|
|
553
|
+
## Performance optimization
|
|
554
|
+
### highlight
|
|
556
555
|
* 配置 `props.highlightConfig.fps` 指定高亮帧率。降低帧率有利于性能。
|
|
557
|
-
|
|
556
|
+
### relative fixed
|
|
558
557
|
* 配置 `props.cellFixedMode` 为 `relative` 时,将使用相对定位实现固定列与固定表头,相较于`sticky`的实现,渲染合成层更少。
|
|
559
558
|
* 问题:若开启了纵向虚拟滚动,不开启横向虚拟滚动,且不设置某些列宽时。如果纵向滚动导致某些列宽变化,则会导致右侧固定列计算错误。
|
|
560
|
-
|
|
561
|
-
* 通过css选择器将 stk-table tbody tr 配置 `transform:translateZ(0)` 对每行 tr
|
|
559
|
+
### tr 分层
|
|
560
|
+
* 通过css选择器将 stk-table tbody tr 配置 `transform:translateZ(0)` 对每行 tr 进行分层。对性能有帮助。
|
|
561
|
+
- 提升合成层可能导致黑底红字字体颜色发生变化。
|
|
562
|
+
- 以下情况尝试开启此功能。
|
|
563
|
+
- 在 `customCell` 较多且复杂时。
|
|
564
|
+
- 大量 highlight 动画时。
|
|
562
565
|
|
|
563
566
|
## Other
|
|
564
567
|
* `$*$` 兼容注释
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn,
|
|
1
|
+
import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn, UniqKeyProp } from './types/index';
|
|
2
2
|
/** Generic stands for DataType */
|
|
3
3
|
type DT = any;
|
|
4
4
|
/**
|
|
@@ -191,7 +191,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
|
|
|
191
191
|
duration?: number | undefined;
|
|
192
192
|
}) => void;
|
|
193
193
|
/** 设置高亮渐暗行 */
|
|
194
|
-
setHighlightDimRow: (rowKeyValues: UniqKey[], option?: {
|
|
194
|
+
setHighlightDimRow: (rowKeyValues: import("./types/index").UniqKey[], option?: {
|
|
195
195
|
method?: "animation" | "css" | "js" | undefined;
|
|
196
196
|
useCss?: boolean | undefined;
|
|
197
197
|
className?: string | undefined;
|
|
@@ -8,7 +8,10 @@ type Sorter<T> = boolean | ((data: T[], option: {
|
|
|
8
8
|
export type CustomCellFunc<T extends Record<string, any>> = (props: {
|
|
9
9
|
row: T;
|
|
10
10
|
col: StkTableColumn<T>;
|
|
11
|
+
/** row[col.dataIndex] 的值 */
|
|
11
12
|
cellValue: any;
|
|
13
|
+
rowIndex: number;
|
|
14
|
+
colIndex: number;
|
|
12
15
|
}) => VNode;
|
|
13
16
|
export type CustomHeaderCellFunc<T extends Record<string, any>> = (props: {
|
|
14
17
|
col: StkTableColumn<T>;
|
|
@@ -12,7 +12,5 @@ type Params<DT extends Record<string, any>> = {
|
|
|
12
12
|
export declare function useColResize<DT extends Record<string, any>>({ tableContainerRef, tableHeaderLast, colResizeIndicatorRef, props, emits, colKeyGen, }: Params<DT>): {
|
|
13
13
|
isColResizing: Ref<boolean>;
|
|
14
14
|
onThResizeMouseDown: (e: MouseEvent, col: StkTableColumn<DT>, isPrev?: boolean) => void;
|
|
15
|
-
onThResizeMouseMove: (e: MouseEvent) => void;
|
|
16
|
-
onThResizeMouseUp: (e: MouseEvent) => void;
|
|
17
15
|
};
|
|
18
16
|
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
type UseTriggerRef<T> = {
|
|
3
|
+
getRef: () => Ref<T>;
|
|
4
|
+
getValue: () => T;
|
|
5
|
+
setValue: (v: T) => void;
|
|
6
|
+
triggerRef: () => void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* 创建一个可触发更新的引用对象。
|
|
10
|
+
* @template T 引用对象的类型。
|
|
11
|
+
* @param initialValue 初始值。
|
|
12
|
+
* @returns 包含获取引用、获取值、设置值和触发更新的函数的对象。
|
|
13
|
+
*/
|
|
14
|
+
export declare function useTriggerRef<T>(initialValue: T): UseTriggerRef<T>;
|
|
15
|
+
export {};
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -260,10 +260,11 @@ function useColResize({
|
|
|
260
260
|
const { clientX } = e;
|
|
261
261
|
const { scrollLeft, scrollTop } = tableContainerRef.value;
|
|
262
262
|
const { left } = tableContainerRef.value.getBoundingClientRect();
|
|
263
|
-
|
|
263
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
264
|
+
let colIndex = tableHeaderLastValue.findIndex((it) => colKeyGen.value(it) === colKeyGen.value(col));
|
|
264
265
|
if (isPrev) {
|
|
265
266
|
colIndex -= 1;
|
|
266
|
-
col =
|
|
267
|
+
col = tableHeaderLastValue[colIndex];
|
|
267
268
|
}
|
|
268
269
|
const offsetTableX = clientX - left + scrollLeft;
|
|
269
270
|
isColResizing.value = true;
|
|
@@ -337,9 +338,7 @@ function useColResize({
|
|
|
337
338
|
}
|
|
338
339
|
return {
|
|
339
340
|
isColResizing,
|
|
340
|
-
onThResizeMouseDown
|
|
341
|
-
onThResizeMouseMove,
|
|
342
|
-
onThResizeMouseUp
|
|
341
|
+
onThResizeMouseDown
|
|
343
342
|
};
|
|
344
343
|
}
|
|
345
344
|
function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableContainerRef }) {
|
|
@@ -350,10 +349,11 @@ function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableCon
|
|
|
350
349
|
const fixedShadowCols = shallowRef([]);
|
|
351
350
|
const fixedColClassMap = computed(() => {
|
|
352
351
|
const colMap = /* @__PURE__ */ new Map();
|
|
352
|
+
const fixedShadowColsValue = fixedShadowCols.value;
|
|
353
353
|
tableHeaders.value.forEach((cols) => {
|
|
354
354
|
cols.forEach((col) => {
|
|
355
355
|
const { showR, showL } = fixedShadow.value;
|
|
356
|
-
const showShadow = props.fixedColShadow && col.fixed && (showL && col.fixed === "left" || showR && col.fixed === "right") &&
|
|
356
|
+
const showShadow = props.fixedColShadow && col.fixed && (showL && col.fixed === "left" || showR && col.fixed === "right") && fixedShadowColsValue.includes(col);
|
|
357
357
|
const classObj = {
|
|
358
358
|
"fixed-cell": col.fixed,
|
|
359
359
|
["fixed-cell--" + col.fixed]: col.fixed,
|
|
@@ -367,10 +367,11 @@ function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableCon
|
|
|
367
367
|
function dealFixedColShadow() {
|
|
368
368
|
if (!props.fixedColShadow)
|
|
369
369
|
return;
|
|
370
|
-
|
|
370
|
+
const fixedShadowColsTemp = [];
|
|
371
371
|
let lastLeftCol = null;
|
|
372
|
-
|
|
373
|
-
|
|
372
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
373
|
+
for (let i = tableHeaderLastValue.length - 1; i >= 0; i--) {
|
|
374
|
+
const col = tableHeaderLastValue[i];
|
|
374
375
|
if (col.fixed === "left") {
|
|
375
376
|
lastLeftCol = col;
|
|
376
377
|
break;
|
|
@@ -379,16 +380,17 @@ function useFixedCol({ props, colKeyGen, tableHeaders, tableHeaderLast, tableCon
|
|
|
379
380
|
let node = { __PARENT__: lastLeftCol };
|
|
380
381
|
while (node = node.__PARENT__) {
|
|
381
382
|
if (node.fixed) {
|
|
382
|
-
|
|
383
|
+
fixedShadowColsTemp.push(node);
|
|
383
384
|
}
|
|
384
385
|
}
|
|
385
|
-
const lastRightCol =
|
|
386
|
+
const lastRightCol = tableHeaderLastValue.find((it) => it.fixed === "right");
|
|
386
387
|
node = { __PARENT__: lastRightCol };
|
|
387
388
|
while (node = node.__PARENT__) {
|
|
388
389
|
if (node.fixed) {
|
|
389
|
-
|
|
390
|
+
fixedShadowColsTemp.push(node);
|
|
390
391
|
}
|
|
391
392
|
}
|
|
393
|
+
fixedShadowCols.value = fixedShadowColsTemp;
|
|
392
394
|
}
|
|
393
395
|
function updateFixedShadow() {
|
|
394
396
|
if (!props.fixedColShadow)
|
|
@@ -877,31 +879,33 @@ function useVirtualScroll({
|
|
|
877
879
|
return props.virtualX && tableHeaderLast.value.reduce((sum, col) => sum += getCalculatedColWidth(col), 0) > virtualScrollX.value.containerWidth + 100;
|
|
878
880
|
});
|
|
879
881
|
const virtualX_columnPart = computed(() => {
|
|
882
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
880
883
|
if (virtualX_on.value) {
|
|
881
884
|
const leftCols = [];
|
|
882
885
|
const rightCols = [];
|
|
883
886
|
const { startIndex, endIndex } = virtualScrollX.value;
|
|
884
887
|
for (let i = 0; i < startIndex; i++) {
|
|
885
|
-
const col =
|
|
886
|
-
if (col.fixed === "left")
|
|
888
|
+
const col = tableHeaderLastValue[i];
|
|
889
|
+
if ((col == null ? void 0 : col.fixed) === "left")
|
|
887
890
|
leftCols.push(col);
|
|
888
891
|
}
|
|
889
|
-
for (let i = endIndex; i <
|
|
890
|
-
const col =
|
|
891
|
-
if (col.fixed === "right")
|
|
892
|
+
for (let i = endIndex; i < tableHeaderLastValue.length; i++) {
|
|
893
|
+
const col = tableHeaderLastValue[i];
|
|
894
|
+
if ((col == null ? void 0 : col.fixed) === "right")
|
|
892
895
|
rightCols.push(col);
|
|
893
896
|
}
|
|
894
|
-
const mainColumns =
|
|
897
|
+
const mainColumns = tableHeaderLastValue.slice(startIndex, endIndex);
|
|
895
898
|
return leftCols.concat(mainColumns).concat(rightCols);
|
|
896
899
|
}
|
|
897
|
-
return
|
|
900
|
+
return tableHeaderLastValue;
|
|
898
901
|
});
|
|
899
902
|
const virtualX_offsetRight = computed(() => {
|
|
900
903
|
if (!virtualX_on.value)
|
|
901
904
|
return 0;
|
|
902
905
|
let width = 0;
|
|
903
|
-
|
|
904
|
-
|
|
906
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
907
|
+
for (let i = virtualScrollX.value.endIndex; i < tableHeaderLastValue.length; i++) {
|
|
908
|
+
const col = tableHeaderLastValue[i];
|
|
905
909
|
if (col.fixed !== "right") {
|
|
906
910
|
width += getCalculatedColWidth(col);
|
|
907
911
|
}
|
|
@@ -909,11 +913,15 @@ function useVirtualScroll({
|
|
|
909
913
|
return width;
|
|
910
914
|
});
|
|
911
915
|
function initVirtualScrollY(height) {
|
|
916
|
+
if (height !== void 0 && typeof height !== "number") {
|
|
917
|
+
console.warn("initVirtualScrollY: height must be a number");
|
|
918
|
+
height = 0;
|
|
919
|
+
}
|
|
912
920
|
if (!virtual_on.value)
|
|
913
921
|
return;
|
|
914
922
|
const { offsetHeight, scrollTop } = tableContainerRef.value || {};
|
|
915
923
|
const { rowHeight } = virtualScroll.value;
|
|
916
|
-
const containerHeight = height
|
|
924
|
+
const containerHeight = height || offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
917
925
|
const { headless, headerRowHeight } = props;
|
|
918
926
|
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
919
927
|
if (!headless) {
|
|
@@ -973,10 +981,10 @@ function useVirtualScroll({
|
|
|
973
981
|
}
|
|
974
982
|
let vue2ScrollXTimeout = null;
|
|
975
983
|
function updateVirtualScrollX(sLeft = 0) {
|
|
976
|
-
var _a;
|
|
977
984
|
if (!props.virtualX)
|
|
978
985
|
return;
|
|
979
|
-
const
|
|
986
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
987
|
+
const headerLength = tableHeaderLastValue == null ? void 0 : tableHeaderLastValue.length;
|
|
980
988
|
if (!headerLength)
|
|
981
989
|
return;
|
|
982
990
|
const { scrollLeft } = virtualScrollX.value;
|
|
@@ -986,7 +994,7 @@ function useVirtualScroll({
|
|
|
986
994
|
let leftColWidthSum = 0;
|
|
987
995
|
let leftFirstColRestWidth = 0;
|
|
988
996
|
for (let colIndex = 0; colIndex < headerLength; colIndex++) {
|
|
989
|
-
const col =
|
|
997
|
+
const col = tableHeaderLastValue[colIndex];
|
|
990
998
|
const colWidth = getCalculatedColWidth(col);
|
|
991
999
|
startIndex++;
|
|
992
1000
|
if (col.fixed === "left") {
|
|
@@ -1005,7 +1013,7 @@ function useVirtualScroll({
|
|
|
1005
1013
|
const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
|
|
1006
1014
|
let endIndex = headerLength;
|
|
1007
1015
|
for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
|
|
1008
|
-
const col =
|
|
1016
|
+
const col = tableHeaderLastValue[colIndex];
|
|
1009
1017
|
colWidthSum += getCalculatedColWidth(col);
|
|
1010
1018
|
if (colWidthSum >= containerWidth) {
|
|
1011
1019
|
endIndex = colIndex + 1;
|
|
@@ -1216,14 +1224,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1216
1224
|
() => props.columns,
|
|
1217
1225
|
() => {
|
|
1218
1226
|
dealColumns();
|
|
1219
|
-
nextTick(
|
|
1227
|
+
nextTick(() => {
|
|
1228
|
+
initVirtualScrollX();
|
|
1229
|
+
dealFixedColShadow();
|
|
1230
|
+
});
|
|
1220
1231
|
}
|
|
1221
1232
|
);
|
|
1222
1233
|
watch(
|
|
1223
1234
|
() => props.virtualX,
|
|
1224
1235
|
() => {
|
|
1225
1236
|
dealColumns();
|
|
1226
|
-
nextTick(
|
|
1237
|
+
nextTick(() => {
|
|
1238
|
+
initVirtualScrollX();
|
|
1239
|
+
dealFixedColShadow();
|
|
1240
|
+
});
|
|
1227
1241
|
}
|
|
1228
1242
|
);
|
|
1229
1243
|
watch(
|
|
@@ -1252,6 +1266,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1252
1266
|
);
|
|
1253
1267
|
watch(() => props.fixedColShadow, dealFixedColShadow);
|
|
1254
1268
|
dealColumns();
|
|
1269
|
+
dealFixedColShadow();
|
|
1255
1270
|
onMounted(() => {
|
|
1256
1271
|
initVirtualScroll();
|
|
1257
1272
|
updateFixedShadow();
|
|
@@ -1264,7 +1279,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1264
1279
|
setSorter(dataIndex, order, { force: false, silent });
|
|
1265
1280
|
}
|
|
1266
1281
|
function dealColumns() {
|
|
1267
|
-
|
|
1282
|
+
let tableHeadersTemp = [];
|
|
1268
1283
|
const copyColumn = props.columns;
|
|
1269
1284
|
const deep = howDeepTheHeader(copyColumn);
|
|
1270
1285
|
const tempHeaderLast = [];
|
|
@@ -1272,8 +1287,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1272
1287
|
console.error("多级表头不支持横向虚拟滚动");
|
|
1273
1288
|
}
|
|
1274
1289
|
function flat(arr, parent, depth = 0) {
|
|
1275
|
-
if (!
|
|
1276
|
-
|
|
1290
|
+
if (!tableHeadersTemp[depth]) {
|
|
1291
|
+
tableHeadersTemp[depth] = [];
|
|
1277
1292
|
}
|
|
1278
1293
|
let allChildrenLen = 0;
|
|
1279
1294
|
let allChildrenWidthSum = 0;
|
|
@@ -1294,7 +1309,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1294
1309
|
colWidth = getColWidth(col);
|
|
1295
1310
|
tempHeaderLast.push(col);
|
|
1296
1311
|
}
|
|
1297
|
-
|
|
1312
|
+
tableHeadersTemp[depth].push(col);
|
|
1298
1313
|
const rowSpan = col.children ? 1 : deep - depth;
|
|
1299
1314
|
const colSpan = colChildrenLen;
|
|
1300
1315
|
if (rowSpan !== 1) {
|
|
@@ -1310,8 +1325,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1310
1325
|
return [allChildrenLen, allChildrenWidthSum];
|
|
1311
1326
|
}
|
|
1312
1327
|
flat(copyColumn, null);
|
|
1328
|
+
tableHeaders.value = tableHeadersTemp;
|
|
1313
1329
|
tableHeaderLast.value = tempHeaderLast;
|
|
1314
|
-
dealFixedColShadow();
|
|
1315
1330
|
}
|
|
1316
1331
|
function rowKeyGen(row) {
|
|
1317
1332
|
if (!row)
|
|
@@ -1706,10 +1721,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1706
1721
|
key: 0,
|
|
1707
1722
|
col,
|
|
1708
1723
|
row,
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
}, null, 8, ["col", "row", "
|
|
1724
|
+
rowIndex,
|
|
1725
|
+
colIndex,
|
|
1726
|
+
cellValue: row[col.dataIndex]
|
|
1727
|
+
}, null, 8, ["col", "row", "rowIndex", "colIndex", "cellValue"])) : (openBlock(), createElementBlock("div", {
|
|
1713
1728
|
key: 1,
|
|
1714
1729
|
class: "table-cell-wrapper",
|
|
1715
1730
|
title: !col.type ? row[col.dataIndex] : ""
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stk-table-vue",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.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",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"author": "japlus",
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
|
35
|
-
"url": "https://
|
|
35
|
+
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
36
36
|
},
|
|
37
37
|
"license": "MIT",
|
|
38
38
|
"devDependencies": {
|
|
@@ -176,9 +176,9 @@
|
|
|
176
176
|
v-if="col.customCell"
|
|
177
177
|
:col="col"
|
|
178
178
|
:row="row"
|
|
179
|
-
:
|
|
180
|
-
:
|
|
181
|
-
:
|
|
179
|
+
:rowIndex="rowIndex"
|
|
180
|
+
:colIndex="colIndex"
|
|
181
|
+
:cellValue="row[col.dataIndex]"
|
|
182
182
|
/>
|
|
183
183
|
<div v-else class="table-cell-wrapper" :title="!col.type ? row[col.dataIndex] : ''">
|
|
184
184
|
<template v-if="col.type === 'seq'">
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
*/
|
|
211
211
|
import { CSSProperties, computed, nextTick, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
|
|
212
212
|
import { DEFAULT_ROW_HEIGHT } from './const';
|
|
213
|
-
import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn, TagType,
|
|
213
|
+
import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn, TagType, UniqKeyProp } from './types/index';
|
|
214
214
|
import { useAutoResize } from './useAutoResize';
|
|
215
215
|
import { useColResize } from './useColResize';
|
|
216
216
|
import { useFixedCol } from './useFixedCol';
|
|
@@ -219,7 +219,7 @@ import { useHighlight } from './useHighlight';
|
|
|
219
219
|
import { useKeyboardArrowScroll } from './useKeyboardArrowScroll';
|
|
220
220
|
import { useThDrag } from './useThDrag';
|
|
221
221
|
import { useVirtualScroll } from './useVirtualScroll';
|
|
222
|
-
import { createStkTableId, getCalculatedColWidth, getColWidth, howDeepTheHeader, tableSort, transformWidthToStr } from './utils';
|
|
222
|
+
import { createStkTableId, getCalculatedColWidth, getColWidth, howDeepTheHeader, tableSort, transformWidthToStr } from './utils/index';
|
|
223
223
|
|
|
224
224
|
/** Generic stands for DataType */
|
|
225
225
|
type DT = any;
|
|
@@ -596,14 +596,22 @@ watch(
|
|
|
596
596
|
() => props.columns,
|
|
597
597
|
() => {
|
|
598
598
|
dealColumns();
|
|
599
|
-
nextTick
|
|
599
|
+
// initVirtualScrollX 需要获取容器滚动宽度等。必须等渲染完成后再调用。因此使用nextTick。
|
|
600
|
+
nextTick(() => {
|
|
601
|
+
initVirtualScrollX();
|
|
602
|
+
dealFixedColShadow();
|
|
603
|
+
});
|
|
600
604
|
},
|
|
601
605
|
);
|
|
602
606
|
watch(
|
|
603
607
|
() => props.virtualX,
|
|
604
608
|
() => {
|
|
605
609
|
dealColumns();
|
|
606
|
-
nextTick
|
|
610
|
+
// initVirtualScrollX 需要获取容器滚动宽度等。必须等渲染完成后再调用。因此使用nextTick。
|
|
611
|
+
nextTick(() => {
|
|
612
|
+
initVirtualScrollX();
|
|
613
|
+
dealFixedColShadow();
|
|
614
|
+
});
|
|
607
615
|
},
|
|
608
616
|
);
|
|
609
617
|
|
|
@@ -637,6 +645,7 @@ watch(
|
|
|
637
645
|
watch(() => props.fixedColShadow, dealFixedColShadow);
|
|
638
646
|
|
|
639
647
|
dealColumns();
|
|
648
|
+
dealFixedColShadow();
|
|
640
649
|
|
|
641
650
|
onMounted(() => {
|
|
642
651
|
initVirtualScroll();
|
|
@@ -656,7 +665,7 @@ function dealDefaultSorter() {
|
|
|
656
665
|
*/
|
|
657
666
|
function dealColumns() {
|
|
658
667
|
// reset
|
|
659
|
-
|
|
668
|
+
let tableHeadersTemp: StkTableColumn<DT>[][] = [];
|
|
660
669
|
const copyColumn = props.columns; // do not deep clone
|
|
661
670
|
const deep = howDeepTheHeader(copyColumn);
|
|
662
671
|
const tempHeaderLast: StkTableColumn<DT>[] = [];
|
|
@@ -673,8 +682,8 @@ function dealColumns() {
|
|
|
673
682
|
* @param parentFixed 父节点固定列继承。
|
|
674
683
|
*/
|
|
675
684
|
function flat(arr: StkTableColumn<DT>[], parent: StkTableColumn<DT> | null, depth = 0 /* , parentFixed: 'left' | 'right' | null = null */) {
|
|
676
|
-
if (!
|
|
677
|
-
|
|
685
|
+
if (!tableHeadersTemp[depth]) {
|
|
686
|
+
tableHeadersTemp[depth] = [];
|
|
678
687
|
}
|
|
679
688
|
/** 所有子节点数量 */
|
|
680
689
|
let allChildrenLen = 0;
|
|
@@ -700,7 +709,7 @@ function dealColumns() {
|
|
|
700
709
|
tempHeaderLast.push(col); // 没有children的列作为colgroup
|
|
701
710
|
}
|
|
702
711
|
// 回溯
|
|
703
|
-
|
|
712
|
+
tableHeadersTemp[depth].push(col);
|
|
704
713
|
const rowSpan = col.children ? 1 : deep - depth;
|
|
705
714
|
const colSpan = colChildrenLen;
|
|
706
715
|
if (rowSpan !== 1) {
|
|
@@ -718,10 +727,8 @@ function dealColumns() {
|
|
|
718
727
|
|
|
719
728
|
flat(copyColumn, null);
|
|
720
729
|
|
|
721
|
-
|
|
722
|
-
|
|
730
|
+
tableHeaders.value = tableHeadersTemp;
|
|
723
731
|
tableHeaderLast.value = tempHeaderLast;
|
|
724
|
-
dealFixedColShadow();
|
|
725
732
|
}
|
|
726
733
|
|
|
727
734
|
/**
|
|
@@ -5,7 +5,15 @@ export type Order = null | 'asc' | 'desc';
|
|
|
5
5
|
|
|
6
6
|
type Sorter<T> = boolean | ((data: T[], option: { order: Order; column: any }) => T[]);
|
|
7
7
|
|
|
8
|
-
export type CustomCellFunc<T extends Record<string, any>> = (props: {
|
|
8
|
+
export type CustomCellFunc<T extends Record<string, any>> = (props: {
|
|
9
|
+
row: T;
|
|
10
|
+
col: StkTableColumn<T>;
|
|
11
|
+
/** row[col.dataIndex] 的值 */
|
|
12
|
+
cellValue: any;
|
|
13
|
+
rowIndex: number;
|
|
14
|
+
colIndex: number;
|
|
15
|
+
}) => VNode;
|
|
16
|
+
|
|
9
17
|
export type CustomHeaderCellFunc<T extends Record<string, any>> = (props: { col: StkTableColumn<T> }) => VNode;
|
|
10
18
|
|
|
11
19
|
/** 表格列配置 */
|
|
@@ -77,12 +77,13 @@ export function useColResize<DT extends Record<string, any>>({
|
|
|
77
77
|
const { clientX } = e;
|
|
78
78
|
const { scrollLeft, scrollTop } = tableContainerRef.value;
|
|
79
79
|
const { left } = tableContainerRef.value.getBoundingClientRect();
|
|
80
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
80
81
|
/** 列下标 */
|
|
81
|
-
let colIndex =
|
|
82
|
+
let colIndex = tableHeaderLastValue.findIndex(it => colKeyGen.value(it) === colKeyGen.value(col));
|
|
82
83
|
if (isPrev) {
|
|
83
84
|
// 上一列
|
|
84
85
|
colIndex -= 1;
|
|
85
|
-
col =
|
|
86
|
+
col = tableHeaderLastValue[colIndex];
|
|
86
87
|
}
|
|
87
88
|
const offsetTableX = clientX - left + scrollLeft;
|
|
88
89
|
|
|
@@ -175,7 +176,5 @@ export function useColResize<DT extends Record<string, any>>({
|
|
|
175
176
|
return {
|
|
176
177
|
isColResizing,
|
|
177
178
|
onThResizeMouseDown,
|
|
178
|
-
onThResizeMouseMove,
|
|
179
|
-
onThResizeMouseUp,
|
|
180
179
|
};
|
|
181
180
|
}
|
|
@@ -29,6 +29,7 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
|
|
|
29
29
|
|
|
30
30
|
const fixedColClassMap = computed(() => {
|
|
31
31
|
const colMap = new Map();
|
|
32
|
+
const fixedShadowColsValue = fixedShadowCols.value;
|
|
32
33
|
tableHeaders.value.forEach(cols => {
|
|
33
34
|
cols.forEach(col => {
|
|
34
35
|
const { showR, showL } = fixedShadow.value;
|
|
@@ -36,7 +37,7 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
|
|
|
36
37
|
props.fixedColShadow &&
|
|
37
38
|
col.fixed &&
|
|
38
39
|
((showL && col.fixed === 'left') || (showR && col.fixed === 'right')) &&
|
|
39
|
-
|
|
40
|
+
fixedShadowColsValue.includes(col);
|
|
40
41
|
const classObj = {
|
|
41
42
|
'fixed-cell': col.fixed,
|
|
42
43
|
['fixed-cell--' + col.fixed]: col.fixed,
|
|
@@ -51,11 +52,13 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
|
|
|
51
52
|
/** 处理固定列阴影 */
|
|
52
53
|
function dealFixedColShadow() {
|
|
53
54
|
if (!props.fixedColShadow) return;
|
|
54
|
-
|
|
55
|
+
const fixedShadowColsTemp = [];
|
|
56
|
+
|
|
55
57
|
// 找到最右边的固定列 findLast
|
|
56
58
|
let lastLeftCol = null;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
60
|
+
for (let i = tableHeaderLastValue.length - 1; i >= 0; i--) {
|
|
61
|
+
const col = tableHeaderLastValue[i];
|
|
59
62
|
if (col.fixed === 'left') {
|
|
60
63
|
lastLeftCol = col;
|
|
61
64
|
break;
|
|
@@ -65,18 +68,20 @@ export function useFixedCol<DT extends Record<string, any>>({ props, colKeyGen,
|
|
|
65
68
|
let node: any = { __PARENT__: lastLeftCol };
|
|
66
69
|
while ((node = node.__PARENT__)) {
|
|
67
70
|
if (node.fixed) {
|
|
68
|
-
|
|
71
|
+
fixedShadowColsTemp.push(node);
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
// 找到最左边的固定列
|
|
73
|
-
const lastRightCol =
|
|
76
|
+
const lastRightCol = tableHeaderLastValue.find(it => it.fixed === 'right');
|
|
74
77
|
node = { __PARENT__: lastRightCol };
|
|
75
78
|
while ((node = node.__PARENT__)) {
|
|
76
79
|
if (node.fixed) {
|
|
77
|
-
|
|
80
|
+
fixedShadowColsTemp.push(node);
|
|
78
81
|
}
|
|
79
82
|
}
|
|
83
|
+
// trigger
|
|
84
|
+
fixedShadowCols.value = fixedShadowColsTemp;
|
|
80
85
|
}
|
|
81
86
|
|
|
82
87
|
/** 滚动条变化时,更新需要展示阴影的列 */
|
|
@@ -103,34 +103,42 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
const virtualX_columnPart = computed(() => {
|
|
106
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
106
107
|
if (virtualX_on.value) {
|
|
107
108
|
// 虚拟横向滚动,固定列要一直保持存在
|
|
108
109
|
const leftCols = [];
|
|
109
110
|
const rightCols = [];
|
|
111
|
+
/**
|
|
112
|
+
* 存在问题:
|
|
113
|
+
* table columns 从多到少时。比方原来的start=5,end=10,现在start=4,end=8。这时候endIndex就超出数组范围了。
|
|
114
|
+
* FIXME: 如果新列数 < endIndex,此时需要重新计算列startIndex和endIndex。
|
|
115
|
+
*/
|
|
110
116
|
const { startIndex, endIndex } = virtualScrollX.value;
|
|
117
|
+
|
|
111
118
|
// 左侧固定列,如果在左边不可见区。则需要拿出来放在前面
|
|
112
119
|
for (let i = 0; i < startIndex; i++) {
|
|
113
|
-
const col =
|
|
114
|
-
if (col
|
|
120
|
+
const col = tableHeaderLastValue[i];
|
|
121
|
+
if (col?.fixed === 'left') leftCols.push(col);
|
|
115
122
|
}
|
|
116
123
|
// 右侧固定列,如果在右边不可见区。则需要拿出来放在后面
|
|
117
|
-
for (let i = endIndex; i <
|
|
118
|
-
const col =
|
|
119
|
-
if (col
|
|
124
|
+
for (let i = endIndex; i < tableHeaderLastValue.length; i++) {
|
|
125
|
+
const col = tableHeaderLastValue[i];
|
|
126
|
+
if (col?.fixed === 'right') rightCols.push(col);
|
|
120
127
|
}
|
|
121
128
|
|
|
122
|
-
const mainColumns =
|
|
129
|
+
const mainColumns = tableHeaderLastValue.slice(startIndex, endIndex);
|
|
123
130
|
|
|
124
131
|
return leftCols.concat(mainColumns).concat(rightCols);
|
|
125
132
|
}
|
|
126
|
-
return
|
|
133
|
+
return tableHeaderLastValue;
|
|
127
134
|
});
|
|
128
135
|
|
|
129
136
|
const virtualX_offsetRight = computed(() => {
|
|
130
137
|
if (!virtualX_on.value) return 0;
|
|
131
138
|
let width = 0;
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
140
|
+
for (let i = virtualScrollX.value.endIndex; i < tableHeaderLastValue.length; i++) {
|
|
141
|
+
const col = tableHeaderLastValue[i];
|
|
134
142
|
if (col.fixed !== 'right') {
|
|
135
143
|
width += getCalculatedColWidth(col);
|
|
136
144
|
}
|
|
@@ -143,10 +151,14 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
143
151
|
* @param {number} [height] 虚拟滚动的高度
|
|
144
152
|
*/
|
|
145
153
|
function initVirtualScrollY(height?: number) {
|
|
154
|
+
if (height !== void 0 && typeof height !== 'number') {
|
|
155
|
+
console.warn('initVirtualScrollY: height must be a number');
|
|
156
|
+
height = 0;
|
|
157
|
+
}
|
|
146
158
|
if (!virtual_on.value) return;
|
|
147
159
|
const { offsetHeight, scrollTop } = tableContainerRef.value || {};
|
|
148
160
|
const { rowHeight } = virtualScroll.value;
|
|
149
|
-
const containerHeight = height
|
|
161
|
+
const containerHeight = height || offsetHeight || DEFAULT_TABLE_HEIGHT;
|
|
150
162
|
const { headless, headerRowHeight } = props;
|
|
151
163
|
let pageSize = Math.ceil(containerHeight / rowHeight);
|
|
152
164
|
if (!headless) {
|
|
@@ -228,7 +240,8 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
228
240
|
/** 通过横向滚动条位置,计算横向虚拟滚动的参数 */
|
|
229
241
|
function updateVirtualScrollX(sLeft = 0) {
|
|
230
242
|
if (!props.virtualX) return;
|
|
231
|
-
const
|
|
243
|
+
const tableHeaderLastValue = tableHeaderLast.value;
|
|
244
|
+
const headerLength = tableHeaderLastValue?.length;
|
|
232
245
|
if (!headerLength) return;
|
|
233
246
|
|
|
234
247
|
const { scrollLeft } = virtualScrollX.value;
|
|
@@ -242,7 +255,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
242
255
|
let leftFirstColRestWidth = 0;
|
|
243
256
|
|
|
244
257
|
for (let colIndex = 0; colIndex < headerLength; colIndex++) {
|
|
245
|
-
const col =
|
|
258
|
+
const col = tableHeaderLastValue[colIndex];
|
|
246
259
|
const colWidth = getCalculatedColWidth(col);
|
|
247
260
|
startIndex++;
|
|
248
261
|
// fixed left 不进入计算列宽
|
|
@@ -264,7 +277,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
264
277
|
const containerWidth = virtualScrollX.value.containerWidth - leftColWidthSum;
|
|
265
278
|
let endIndex = headerLength;
|
|
266
279
|
for (let colIndex = startIndex + 1; colIndex < headerLength; colIndex++) {
|
|
267
|
-
const col =
|
|
280
|
+
const col = tableHeaderLastValue[colIndex];
|
|
268
281
|
colWidthSum += getCalculatedColWidth(col);
|
|
269
282
|
// 列宽大于容器宽度则停止
|
|
270
283
|
if (colWidthSum >= containerWidth) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DEFAULT_COL_WIDTH, STK_ID_PREFIX } from '
|
|
2
|
-
import { Order, SortConfig, SortOption, SortState, StkTableColumn } from '
|
|
1
|
+
import { DEFAULT_COL_WIDTH, STK_ID_PREFIX } from '../const';
|
|
2
|
+
import { Order, SortConfig, SortOption, SortState, StkTableColumn } from '../types';
|
|
3
3
|
|
|
4
4
|
/** 是否空值 */
|
|
5
5
|
function isEmptyValue(val: any, isNumber?: boolean) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Ref, shallowRef } from 'vue';
|
|
2
|
+
|
|
3
|
+
type UseTriggerRef<T> = {
|
|
4
|
+
getRef: () => Ref<T>;
|
|
5
|
+
getValue: () => T;
|
|
6
|
+
setValue: (v: T) => void;
|
|
7
|
+
triggerRef: () => void;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* 创建一个可触发更新的引用对象。
|
|
11
|
+
* @template T 引用对象的类型。
|
|
12
|
+
* @param initialValue 初始值。
|
|
13
|
+
* @returns 包含获取引用、获取值、设置值和触发更新的函数的对象。
|
|
14
|
+
*/
|
|
15
|
+
export function useTriggerRef<T>(initialValue: T): UseTriggerRef<T> {
|
|
16
|
+
let value = initialValue;
|
|
17
|
+
const ref = shallowRef(value);
|
|
18
|
+
|
|
19
|
+
function getValue() {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function setValue(v: T) {
|
|
23
|
+
value = v;
|
|
24
|
+
}
|
|
25
|
+
function getRef() {
|
|
26
|
+
return ref;
|
|
27
|
+
}
|
|
28
|
+
function triggerRef() {
|
|
29
|
+
ref.value = value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { getRef, getValue, setValue, triggerRef };
|
|
33
|
+
}
|