stk-table-vue 0.4.5 → 0.4.8
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 +3 -0
- package/lib/src/StkTable/StkTable.vue.d.ts +52 -49
- package/lib/stk-table-vue.js +97 -93
- package/lib/style.css +7 -4
- package/package.json +64 -64
- package/src/StkTable/StkTable.vue +29 -38
- package/src/StkTable/style.less +9 -5
- package/src/StkTable/useFixedStyle.ts +3 -3
- package/src/StkTable/useKeyboardArrowScroll.ts +18 -8
- package/src/StkTable/useVirtualScroll.ts +23 -25
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ repo:
|
|
|
13
13
|
## Bug TODO:
|
|
14
14
|
* [x] props.dataSource 为 shallowRef 时,高亮行不生效。(bug:2024.02.21)(resolved:0.2.3)
|
|
15
15
|
* [] 固定列列宽拖动目标。
|
|
16
|
+
* [] 惯性滚动优化。
|
|
16
17
|
|
|
17
18
|
## Feature TODO:
|
|
18
19
|
* [x] 高亮行,单元格。
|
|
@@ -587,6 +588,8 @@ export type SortConfig<T extends Record<string, any>> = {
|
|
|
587
588
|
- 以下情况尝试开启此功能。
|
|
588
589
|
- 在 `customCell` 较多且复杂时。
|
|
589
590
|
- 大量 highlight 动画时。
|
|
591
|
+
### props.autoResize
|
|
592
|
+
* 手动设置为 `props.autoResize=false`。可取消监听的性能消耗。适用于宽度高度不变的表格。
|
|
590
593
|
|
|
591
594
|
## Tips
|
|
592
595
|
### props.fixedMode
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HighlightConfig, Order, SeqConfig, SortConfig, SortOption, SortState, StkTableColumn, UniqKeyProp } from './types/index';
|
|
2
2
|
|
|
3
3
|
/** Generic stands for DataType */
|
|
4
|
-
type DT =
|
|
4
|
+
type DT = any;
|
|
5
5
|
/**
|
|
6
6
|
* 选中一行,
|
|
7
7
|
* @param {string} rowKey selected rowKey, null to unselect
|
|
@@ -24,7 +24,7 @@ declare function setSorter(dataIndex: string, order: Order, option?: {
|
|
|
24
24
|
force?: boolean;
|
|
25
25
|
silent?: boolean;
|
|
26
26
|
sort?: boolean;
|
|
27
|
-
}):
|
|
27
|
+
}): any[];
|
|
28
28
|
/** 重置排序 */
|
|
29
29
|
declare function resetSorter(): void;
|
|
30
30
|
/**
|
|
@@ -34,7 +34,7 @@ declare function resetSorter(): void;
|
|
|
34
34
|
*/
|
|
35
35
|
declare function scrollTo(top?: number | null, left?: number | null): void;
|
|
36
36
|
/** 获取当前状态的表格数据 */
|
|
37
|
-
declare function getTableData():
|
|
37
|
+
declare function getTableData(): any[];
|
|
38
38
|
/** 获取当前排序列的信息 */
|
|
39
39
|
declare function getSortColumns(): Partial<SortState<DT>>[];
|
|
40
40
|
declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
|
|
@@ -66,17 +66,17 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
66
66
|
/** x轴虚拟滚动(必须设置列宽)*/
|
|
67
67
|
virtualX?: boolean | undefined;
|
|
68
68
|
/** 表格列配置 */
|
|
69
|
-
columns?: StkTableColumn<
|
|
69
|
+
columns?: StkTableColumn<any>[] | undefined;
|
|
70
70
|
/** 表格数据源 */
|
|
71
|
-
dataSource?:
|
|
71
|
+
dataSource?: any[] | undefined;
|
|
72
72
|
/** 行唯一键 (行唯一值不能为undefined) */
|
|
73
73
|
rowKey?: UniqKeyProp | undefined;
|
|
74
74
|
/** 列唯一键 */
|
|
75
75
|
colKey?: UniqKeyProp | undefined;
|
|
76
76
|
/** 空值展示文字 */
|
|
77
77
|
emptyCellText?: string | ((option: {
|
|
78
|
-
row:
|
|
79
|
-
col: StkTableColumn<
|
|
78
|
+
row: any;
|
|
79
|
+
col: StkTableColumn<any>;
|
|
80
80
|
}) => string) | undefined;
|
|
81
81
|
/** 暂无数据兜底高度是否撑满 */
|
|
82
82
|
noDataFull?: boolean | undefined;
|
|
@@ -93,12 +93,12 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
93
93
|
/** 是否高亮鼠标悬浮的单元格 */
|
|
94
94
|
cellHover?: boolean | undefined;
|
|
95
95
|
/** 表头是否可拖动。支持回调函数。 */
|
|
96
|
-
headerDrag?: boolean | ((col: StkTableColumn<
|
|
96
|
+
headerDrag?: boolean | ((col: StkTableColumn<any>) => boolean) | undefined;
|
|
97
97
|
/**
|
|
98
98
|
* 给行附加className<br>
|
|
99
99
|
* FIXME: 是否需要优化,因为不传此prop会使表格行一直执行空函数,是否有影响
|
|
100
100
|
*/
|
|
101
|
-
rowClassName?: ((row:
|
|
101
|
+
rowClassName?: ((row: any, i: number) => string) | undefined;
|
|
102
102
|
/**
|
|
103
103
|
* 列宽是否可拖动<br>
|
|
104
104
|
* **不要设置**列minWidth,**必须**设置width<br>
|
|
@@ -126,7 +126,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
126
126
|
/** 优化vue2 滚动 */
|
|
127
127
|
optimizeVue2Scroll?: boolean | undefined;
|
|
128
128
|
/** 排序配置 */
|
|
129
|
-
sortConfig?: SortConfig<
|
|
129
|
+
sortConfig?: SortConfig<any> | undefined;
|
|
130
130
|
/** 隐藏头部title。可传入dataIndex数组 */
|
|
131
131
|
hideHeaderTitle?: boolean | string[] | undefined;
|
|
132
132
|
/** 高亮配置 */
|
|
@@ -197,7 +197,10 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
197
197
|
setCurrentRow: typeof setCurrentRow;
|
|
198
198
|
/** 设置高亮渐暗单元格 */
|
|
199
199
|
setHighlightDimCell: (rowKeyValue: string, dataIndex: string, option?: {
|
|
200
|
-
className?: string | undefined;
|
|
200
|
+
className?: string | undefined; /**
|
|
201
|
+
* 排序变更触发
|
|
202
|
+
* ```(col: StkTableColumn<DT>, order: Order, data: DT[])```
|
|
203
|
+
*/
|
|
201
204
|
method?: "animation" | "css" | undefined;
|
|
202
205
|
keyframe?: Keyframe[] | PropertyIndexedKeyframes | null | undefined;
|
|
203
206
|
duration?: number | undefined;
|
|
@@ -211,7 +214,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
211
214
|
duration?: number | undefined;
|
|
212
215
|
}) => void;
|
|
213
216
|
/** 表格排序列dataIndex */
|
|
214
|
-
sortCol: import('vue').Ref<string | number | undefined>;
|
|
217
|
+
sortCol: import('vue').Ref<string | number | symbol | undefined>;
|
|
215
218
|
/** 获取当前排序状态 */
|
|
216
219
|
getSortColumns: typeof getSortColumns;
|
|
217
220
|
/** 设置排序 */
|
|
@@ -223,19 +226,19 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
223
226
|
/** 获取表格数据 */
|
|
224
227
|
getTableData: typeof getTableData;
|
|
225
228
|
}, unknown, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
226
|
-
"sort-change": (col: StkTableColumn<
|
|
227
|
-
"row-click": (ev: MouseEvent, row:
|
|
228
|
-
"current-change": (ev: MouseEvent | null, row:
|
|
229
|
+
"sort-change": (col: StkTableColumn<any>, order: Order, data: any[], sortConfig: SortConfig<any>) => void;
|
|
230
|
+
"row-click": (ev: MouseEvent, row: any) => void;
|
|
231
|
+
"current-change": (ev: MouseEvent | null, row: any, data: {
|
|
229
232
|
select: boolean;
|
|
230
233
|
}) => void;
|
|
231
|
-
"row-dblclick": (ev: MouseEvent, row:
|
|
234
|
+
"row-dblclick": (ev: MouseEvent, row: any) => void;
|
|
232
235
|
"header-row-menu": (ev: MouseEvent) => void;
|
|
233
|
-
"row-menu": (ev: MouseEvent, row:
|
|
234
|
-
"cell-click": (ev: MouseEvent, row:
|
|
235
|
-
"cell-mouseenter": (ev: MouseEvent, row:
|
|
236
|
-
"cell-mouseleave": (ev: MouseEvent, row:
|
|
237
|
-
"cell-mouseover": (ev: MouseEvent, row:
|
|
238
|
-
"header-cell-click": (ev: MouseEvent, col: StkTableColumn<
|
|
236
|
+
"row-menu": (ev: MouseEvent, row: any) => void;
|
|
237
|
+
"cell-click": (ev: MouseEvent, row: any, col: StkTableColumn<any>) => void;
|
|
238
|
+
"cell-mouseenter": (ev: MouseEvent, row: any, col: StkTableColumn<any>) => void;
|
|
239
|
+
"cell-mouseleave": (ev: MouseEvent, row: any, col: StkTableColumn<any>) => void;
|
|
240
|
+
"cell-mouseover": (ev: MouseEvent, row: any, col: StkTableColumn<any>) => void;
|
|
241
|
+
"header-cell-click": (ev: MouseEvent, col: StkTableColumn<any>) => void;
|
|
239
242
|
scroll: (ev: Event, data: {
|
|
240
243
|
startIndex: number;
|
|
241
244
|
endIndex: number;
|
|
@@ -244,7 +247,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
244
247
|
"col-order-change": (dragStartKey: string, targetColKey: string) => void;
|
|
245
248
|
"th-drag-start": (dragStartKey: string) => void;
|
|
246
249
|
"th-drop": (targetColKey: string) => void;
|
|
247
|
-
"update:columns": (cols: StkTableColumn<
|
|
250
|
+
"update:columns": (cols: StkTableColumn<any>[]) => void;
|
|
248
251
|
}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
|
|
249
252
|
width?: string | undefined;
|
|
250
253
|
/** 最小表格宽度 */
|
|
@@ -274,17 +277,17 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
274
277
|
/** x轴虚拟滚动(必须设置列宽)*/
|
|
275
278
|
virtualX?: boolean | undefined;
|
|
276
279
|
/** 表格列配置 */
|
|
277
|
-
columns?: StkTableColumn<
|
|
280
|
+
columns?: StkTableColumn<any>[] | undefined;
|
|
278
281
|
/** 表格数据源 */
|
|
279
|
-
dataSource?:
|
|
282
|
+
dataSource?: any[] | undefined;
|
|
280
283
|
/** 行唯一键 (行唯一值不能为undefined) */
|
|
281
284
|
rowKey?: UniqKeyProp | undefined;
|
|
282
285
|
/** 列唯一键 */
|
|
283
286
|
colKey?: UniqKeyProp | undefined;
|
|
284
287
|
/** 空值展示文字 */
|
|
285
288
|
emptyCellText?: string | ((option: {
|
|
286
|
-
row:
|
|
287
|
-
col: StkTableColumn<
|
|
289
|
+
row: any;
|
|
290
|
+
col: StkTableColumn<any>;
|
|
288
291
|
}) => string) | undefined;
|
|
289
292
|
/** 暂无数据兜底高度是否撑满 */
|
|
290
293
|
noDataFull?: boolean | undefined;
|
|
@@ -301,12 +304,12 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
301
304
|
/** 是否高亮鼠标悬浮的单元格 */
|
|
302
305
|
cellHover?: boolean | undefined;
|
|
303
306
|
/** 表头是否可拖动。支持回调函数。 */
|
|
304
|
-
headerDrag?: boolean | ((col: StkTableColumn<
|
|
307
|
+
headerDrag?: boolean | ((col: StkTableColumn<any>) => boolean) | undefined;
|
|
305
308
|
/**
|
|
306
309
|
* 给行附加className<br>
|
|
307
310
|
* FIXME: 是否需要优化,因为不传此prop会使表格行一直执行空函数,是否有影响
|
|
308
311
|
*/
|
|
309
|
-
rowClassName?: ((row:
|
|
312
|
+
rowClassName?: ((row: any, i: number) => string) | undefined;
|
|
310
313
|
/**
|
|
311
314
|
* 列宽是否可拖动<br>
|
|
312
315
|
* **不要设置**列minWidth,**必须**设置width<br>
|
|
@@ -334,7 +337,7 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
334
337
|
/** 优化vue2 滚动 */
|
|
335
338
|
optimizeVue2Scroll?: boolean | undefined;
|
|
336
339
|
/** 排序配置 */
|
|
337
|
-
sortConfig?: SortConfig<
|
|
340
|
+
sortConfig?: SortConfig<any> | undefined;
|
|
338
341
|
/** 隐藏头部title。可传入dataIndex数组 */
|
|
339
342
|
hideHeaderTitle?: boolean | string[] | undefined;
|
|
340
343
|
/** 高亮配置 */
|
|
@@ -399,23 +402,23 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
399
402
|
startIndex: number;
|
|
400
403
|
endIndex: number;
|
|
401
404
|
}) => any) | undefined;
|
|
402
|
-
"onUpdate:columns"?: ((cols: StkTableColumn<
|
|
405
|
+
"onUpdate:columns"?: ((cols: StkTableColumn<any>[]) => any) | undefined;
|
|
403
406
|
"onTh-drag-start"?: ((dragStartKey: string) => any) | undefined;
|
|
404
407
|
"onCol-order-change"?: ((dragStartKey: string, targetColKey: string) => any) | undefined;
|
|
405
408
|
"onTh-drop"?: ((targetColKey: string) => any) | undefined;
|
|
406
|
-
"onSort-change"?: ((col: StkTableColumn<
|
|
407
|
-
"onRow-click"?: ((ev: MouseEvent, row:
|
|
408
|
-
"onCurrent-change"?: ((ev: MouseEvent | null, row:
|
|
409
|
+
"onSort-change"?: ((col: StkTableColumn<any>, order: Order, data: any[], sortConfig: SortConfig<any>) => any) | undefined;
|
|
410
|
+
"onRow-click"?: ((ev: MouseEvent, row: any) => any) | undefined;
|
|
411
|
+
"onCurrent-change"?: ((ev: MouseEvent | null, row: any, data: {
|
|
409
412
|
select: boolean;
|
|
410
413
|
}) => any) | undefined;
|
|
411
|
-
"onRow-dblclick"?: ((ev: MouseEvent, row:
|
|
414
|
+
"onRow-dblclick"?: ((ev: MouseEvent, row: any) => any) | undefined;
|
|
412
415
|
"onHeader-row-menu"?: ((ev: MouseEvent) => any) | undefined;
|
|
413
|
-
"onRow-menu"?: ((ev: MouseEvent, row:
|
|
414
|
-
"onCell-click"?: ((ev: MouseEvent, row:
|
|
415
|
-
"onCell-mouseenter"?: ((ev: MouseEvent, row:
|
|
416
|
-
"onCell-mouseleave"?: ((ev: MouseEvent, row:
|
|
417
|
-
"onCell-mouseover"?: ((ev: MouseEvent, row:
|
|
418
|
-
"onHeader-cell-click"?: ((ev: MouseEvent, col: StkTableColumn<
|
|
416
|
+
"onRow-menu"?: ((ev: MouseEvent, row: any) => any) | undefined;
|
|
417
|
+
"onCell-click"?: ((ev: MouseEvent, row: any, col: StkTableColumn<any>) => any) | undefined;
|
|
418
|
+
"onCell-mouseenter"?: ((ev: MouseEvent, row: any, col: StkTableColumn<any>) => any) | undefined;
|
|
419
|
+
"onCell-mouseleave"?: ((ev: MouseEvent, row: any, col: StkTableColumn<any>) => any) | undefined;
|
|
420
|
+
"onCell-mouseover"?: ((ev: MouseEvent, row: any, col: StkTableColumn<any>) => any) | undefined;
|
|
421
|
+
"onHeader-cell-click"?: ((ev: MouseEvent, col: StkTableColumn<any>) => any) | undefined;
|
|
419
422
|
"onScroll-x"?: ((ev: Event) => any) | undefined;
|
|
420
423
|
}, {
|
|
421
424
|
width: string;
|
|
@@ -432,13 +435,13 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
432
435
|
rowCurrentRevokable: boolean;
|
|
433
436
|
virtual: boolean;
|
|
434
437
|
virtualX: boolean;
|
|
435
|
-
columns: StkTableColumn<
|
|
436
|
-
dataSource:
|
|
438
|
+
columns: StkTableColumn<any>[];
|
|
439
|
+
dataSource: any[];
|
|
437
440
|
rowKey: UniqKeyProp;
|
|
438
441
|
colKey: UniqKeyProp;
|
|
439
442
|
emptyCellText: string | ((option: {
|
|
440
|
-
row:
|
|
441
|
-
col: StkTableColumn<
|
|
443
|
+
row: any;
|
|
444
|
+
col: StkTableColumn<any>;
|
|
442
445
|
}) => string);
|
|
443
446
|
noDataFull: boolean;
|
|
444
447
|
showNoData: boolean;
|
|
@@ -447,22 +450,22 @@ declare const _default: __VLS_WithTemplateSlots<import('vue').DefineComponent<__
|
|
|
447
450
|
showOverflow: boolean;
|
|
448
451
|
showTrHoverClass: boolean;
|
|
449
452
|
cellHover: boolean;
|
|
450
|
-
headerDrag: boolean | ((col: StkTableColumn<
|
|
451
|
-
rowClassName: (row:
|
|
453
|
+
headerDrag: boolean | ((col: StkTableColumn<any>) => boolean);
|
|
454
|
+
rowClassName: (row: any, i: number) => string;
|
|
452
455
|
colResizable: boolean;
|
|
453
456
|
colMinWidth: number;
|
|
454
457
|
bordered: boolean | "h" | "v" | "body-v";
|
|
455
458
|
autoResize: boolean | (() => void);
|
|
456
459
|
fixedColShadow: boolean;
|
|
457
460
|
optimizeVue2Scroll: boolean;
|
|
458
|
-
sortConfig: SortConfig<
|
|
461
|
+
sortConfig: SortConfig<any>;
|
|
459
462
|
hideHeaderTitle: boolean | string[];
|
|
460
463
|
highlightConfig: HighlightConfig;
|
|
461
464
|
seqConfig: SeqConfig;
|
|
462
465
|
cellFixedMode: "sticky" | "relative";
|
|
463
466
|
}, {}>, {
|
|
464
467
|
tableHeader?(_: {
|
|
465
|
-
col: StkTableColumn<
|
|
468
|
+
col: StkTableColumn<any>;
|
|
466
469
|
}): any;
|
|
467
470
|
empty?(_: {}): any;
|
|
468
471
|
}>;
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -455,8 +455,6 @@ function useFixedStyle({
|
|
|
455
455
|
if (tagType === TagType.TD && !fixed)
|
|
456
456
|
return null;
|
|
457
457
|
const style = {};
|
|
458
|
-
const { scrollLeft, scrollWidth, offsetLeft, containerWidth } = virtualScrollX.value;
|
|
459
|
-
const scrollRight = scrollWidth - containerWidth - scrollLeft;
|
|
460
458
|
const isFixedLeft = fixed === "left";
|
|
461
459
|
if (tagType === TagType.TH) {
|
|
462
460
|
if (isRelativeMode.value) {
|
|
@@ -465,6 +463,8 @@ function useFixedStyle({
|
|
|
465
463
|
style.top = depth * props.rowHeight + "px";
|
|
466
464
|
}
|
|
467
465
|
}
|
|
466
|
+
const { scrollLeft, scrollWidth, offsetLeft, containerWidth } = virtualScrollX.value;
|
|
467
|
+
const scrollRight = scrollWidth - containerWidth - scrollLeft;
|
|
468
468
|
if (fixed === "left" || fixed === "right") {
|
|
469
469
|
if (isRelativeMode.value) {
|
|
470
470
|
if (isFixedLeft) {
|
|
@@ -740,7 +740,16 @@ function useHighlight({ props, stkTableId, tableContainerRef }) {
|
|
|
740
740
|
setHighlightDimCell
|
|
741
741
|
};
|
|
742
742
|
}
|
|
743
|
-
|
|
743
|
+
var ScrollCodes = /* @__PURE__ */ ((ScrollCodes2) => {
|
|
744
|
+
ScrollCodes2["ArrowUp"] = "ArrowUp";
|
|
745
|
+
ScrollCodes2["ArrowRight"] = "ArrowRight";
|
|
746
|
+
ScrollCodes2["ArrowDown"] = "ArrowDown";
|
|
747
|
+
ScrollCodes2["ArrowLeft"] = "ArrowLeft";
|
|
748
|
+
ScrollCodes2["PageUp"] = "PageUp";
|
|
749
|
+
ScrollCodes2["PageDown"] = "PageDown";
|
|
750
|
+
return ScrollCodes2;
|
|
751
|
+
})(ScrollCodes || {});
|
|
752
|
+
const ScrollCodesValues = Object.values(ScrollCodes);
|
|
744
753
|
function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on }) {
|
|
745
754
|
let isMouseOver = false;
|
|
746
755
|
watch(virtual_on, (val) => {
|
|
@@ -767,7 +776,9 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
767
776
|
(_c = targetElement.value) == null ? void 0 : _c.removeEventListener("mousedown", handleMouseDown);
|
|
768
777
|
}
|
|
769
778
|
function handleKeydown(e) {
|
|
770
|
-
if (!
|
|
779
|
+
if (!virtual_on.value)
|
|
780
|
+
return;
|
|
781
|
+
if (!ScrollCodesValues.includes(e.code))
|
|
771
782
|
return;
|
|
772
783
|
if (!isMouseOver)
|
|
773
784
|
return;
|
|
@@ -777,17 +788,17 @@ function useKeyboardArrowScroll(targetElement, { props, scrollTo, virtualScroll,
|
|
|
777
788
|
const { headless, headerRowHeight } = props;
|
|
778
789
|
const headerHeight = headless ? 0 : tableHeaders.value.length * (headerRowHeight || rowHeight);
|
|
779
790
|
const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
|
|
780
|
-
if (e.code ===
|
|
791
|
+
if (e.code === "ArrowUp") {
|
|
781
792
|
scrollTo(scrollTop - rowHeight, null);
|
|
782
|
-
} else if (e.code ===
|
|
793
|
+
} else if (e.code === "ArrowRight") {
|
|
783
794
|
scrollTo(null, scrollLeft + rowHeight);
|
|
784
|
-
} else if (e.code ===
|
|
795
|
+
} else if (e.code === "ArrowDown") {
|
|
785
796
|
scrollTo(scrollTop + rowHeight, null);
|
|
786
|
-
} else if (e.code ===
|
|
797
|
+
} else if (e.code === "ArrowLeft") {
|
|
787
798
|
scrollTo(null, scrollLeft - rowHeight);
|
|
788
|
-
} else if (e.code ===
|
|
799
|
+
} else if (e.code === "PageUp") {
|
|
789
800
|
scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
|
|
790
|
-
} else if (e.code ===
|
|
801
|
+
} else if (e.code === "PageDown") {
|
|
791
802
|
scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
|
|
792
803
|
}
|
|
793
804
|
}
|
|
@@ -937,6 +948,10 @@ function useVirtualScroll({
|
|
|
937
948
|
const { headerRowHeight } = props;
|
|
938
949
|
return headerRowHeight * tableHeaders.value.length;
|
|
939
950
|
}
|
|
951
|
+
function initVirtualScroll(height) {
|
|
952
|
+
initVirtualScrollY(height);
|
|
953
|
+
initVirtualScrollX();
|
|
954
|
+
}
|
|
940
955
|
function initVirtualScrollY(height) {
|
|
941
956
|
var _a;
|
|
942
957
|
if (height !== void 0 && typeof height !== "number") {
|
|
@@ -954,7 +969,7 @@ function useVirtualScroll({
|
|
|
954
969
|
const headerHeight = getTableHeaderHeight();
|
|
955
970
|
tableHeaderHeight.value = headerHeight;
|
|
956
971
|
if (!headless) {
|
|
957
|
-
const headerToBodyRowHeightCount = Math.floor(headerHeight
|
|
972
|
+
const headerToBodyRowHeightCount = Math.floor(headerHeight / rowHeight);
|
|
958
973
|
pageSize -= headerToBodyRowHeightCount;
|
|
959
974
|
}
|
|
960
975
|
const maxScrollTop = dataSourceCopy.value.length * rowHeight + tableHeaderHeight.value - containerHeight;
|
|
@@ -970,31 +985,21 @@ function useVirtualScroll({
|
|
|
970
985
|
virtualScrollX.value.scrollWidth = scrollWidth || DEFAULT_TABLE_WIDTH;
|
|
971
986
|
updateVirtualScrollX(scrollLeft);
|
|
972
987
|
}
|
|
973
|
-
function initVirtualScroll(height) {
|
|
974
|
-
initVirtualScrollY(height);
|
|
975
|
-
initVirtualScrollX();
|
|
976
|
-
}
|
|
977
988
|
let vue2ScrollYTimeout = null;
|
|
978
989
|
function updateVirtualScrollY(sTop = 0) {
|
|
979
|
-
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex } = virtualScroll.value;
|
|
990
|
+
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex, endIndex: oldEndIndex } = virtualScroll.value;
|
|
980
991
|
virtualScroll.value.scrollTop = sTop;
|
|
981
992
|
if (!virtual_on.value) {
|
|
982
993
|
return;
|
|
983
994
|
}
|
|
984
995
|
let startIndex = Math.floor(sTop / rowHeight);
|
|
985
|
-
|
|
986
|
-
startIndex = 0;
|
|
987
|
-
}
|
|
996
|
+
let endIndex = startIndex + pageSize;
|
|
988
997
|
if (props.stripe && startIndex !== 0) {
|
|
989
|
-
|
|
990
|
-
if (scrollRows % 2) {
|
|
998
|
+
if (startIndex % 2) {
|
|
991
999
|
startIndex -= 1;
|
|
992
1000
|
}
|
|
993
1001
|
}
|
|
994
|
-
|
|
995
|
-
if (props.stripe) {
|
|
996
|
-
endIndex += 1;
|
|
997
|
-
}
|
|
1002
|
+
startIndex = Math.max(0, startIndex);
|
|
998
1003
|
endIndex = Math.min(endIndex, dataSourceCopy.value.length);
|
|
999
1004
|
if (startIndex >= endIndex) {
|
|
1000
1005
|
startIndex = endIndex - pageSize;
|
|
@@ -1002,13 +1007,12 @@ function useVirtualScroll({
|
|
|
1002
1007
|
if (vue2ScrollYTimeout) {
|
|
1003
1008
|
window.clearTimeout(vue2ScrollYTimeout);
|
|
1004
1009
|
}
|
|
1010
|
+
if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1005
1013
|
const offsetTop = startIndex * rowHeight;
|
|
1006
1014
|
if (!props.optimizeVue2Scroll || sTop <= scrollTop || Math.abs(oldStartIndex - startIndex) >= pageSize) {
|
|
1007
|
-
Object.assign(virtualScroll.value, {
|
|
1008
|
-
startIndex,
|
|
1009
|
-
endIndex,
|
|
1010
|
-
offsetTop
|
|
1011
|
-
});
|
|
1015
|
+
Object.assign(virtualScroll.value, { startIndex, endIndex, offsetTop });
|
|
1012
1016
|
} else {
|
|
1013
1017
|
virtualScroll.value.endIndex = endIndex;
|
|
1014
1018
|
vue2ScrollYTimeout = window.setTimeout(() => {
|
|
@@ -1087,17 +1091,16 @@ function useVirtualScroll({
|
|
|
1087
1091
|
};
|
|
1088
1092
|
}
|
|
1089
1093
|
const _hoisted_1 = ["data-col-key", "draggable", "rowspan", "colspan", "title", "onClick"];
|
|
1090
|
-
const _hoisted_2 = {
|
|
1091
|
-
const _hoisted_3 = {
|
|
1094
|
+
const _hoisted_2 = {
|
|
1092
1095
|
key: 1,
|
|
1093
1096
|
class: "table-header-title"
|
|
1094
1097
|
};
|
|
1095
|
-
const
|
|
1096
|
-
const
|
|
1098
|
+
const _hoisted_3 = { class: "table-header-title" };
|
|
1099
|
+
const _hoisted_4 = {
|
|
1097
1100
|
key: 3,
|
|
1098
1101
|
class: "table-header-sorter"
|
|
1099
1102
|
};
|
|
1100
|
-
const
|
|
1103
|
+
const _hoisted_5 = /* @__PURE__ */ createElementVNode("svg", {
|
|
1101
1104
|
xmlns: "http://www.w3.org/2000/svg",
|
|
1102
1105
|
width: "16px",
|
|
1103
1106
|
height: "16px",
|
|
@@ -1114,31 +1117,22 @@ const _hoisted_6 = /* @__PURE__ */ createElementVNode("svg", {
|
|
|
1114
1117
|
points: "8 10 4.8 14 11.2 14"
|
|
1115
1118
|
})
|
|
1116
1119
|
], -1);
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1120
|
+
const _hoisted_6 = [
|
|
1121
|
+
_hoisted_5
|
|
1119
1122
|
];
|
|
1123
|
+
const _hoisted_7 = ["onMousedown"];
|
|
1120
1124
|
const _hoisted_8 = ["onMousedown"];
|
|
1121
|
-
const _hoisted_9 =
|
|
1122
|
-
const _hoisted_10 = {
|
|
1123
|
-
key: 1,
|
|
1124
|
-
class: "virtual-top"
|
|
1125
|
-
};
|
|
1126
|
-
const _hoisted_11 = {
|
|
1125
|
+
const _hoisted_9 = {
|
|
1127
1126
|
key: 0,
|
|
1128
|
-
class: "
|
|
1127
|
+
class: "vt-x-left"
|
|
1129
1128
|
};
|
|
1130
|
-
const
|
|
1131
|
-
const
|
|
1132
|
-
const _hoisted_14 = {
|
|
1129
|
+
const _hoisted_10 = ["id", "data-row-key", "onClick", "onDblclick", "onContextmenu", "onMouseover"];
|
|
1130
|
+
const _hoisted_11 = {
|
|
1133
1131
|
key: 0,
|
|
1134
|
-
class: "
|
|
1135
|
-
};
|
|
1136
|
-
const _hoisted_15 = ["data-index", "onClick", "onMouseenter", "onMouseleave", "onMouseover"];
|
|
1137
|
-
const _hoisted_16 = ["title"];
|
|
1138
|
-
const _hoisted_17 = {
|
|
1139
|
-
key: 2,
|
|
1140
|
-
class: "virtual-bottom"
|
|
1132
|
+
class: "vt-x-left"
|
|
1141
1133
|
};
|
|
1134
|
+
const _hoisted_12 = ["data-index", "onClick", "onMouseenter", "onMouseleave", "onMouseover"];
|
|
1135
|
+
const _hoisted_13 = ["title"];
|
|
1142
1136
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
1143
1137
|
__name: "StkTable",
|
|
1144
1138
|
props: {
|
|
@@ -1283,6 +1277,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1283
1277
|
});
|
|
1284
1278
|
}
|
|
1285
1279
|
);
|
|
1280
|
+
watch(
|
|
1281
|
+
() => props.virtual,
|
|
1282
|
+
() => {
|
|
1283
|
+
nextTick(() => {
|
|
1284
|
+
initVirtualScrollY();
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
);
|
|
1286
1288
|
watch(
|
|
1287
1289
|
() => props.virtualX,
|
|
1288
1290
|
() => {
|
|
@@ -1580,15 +1582,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1580
1582
|
function setCurrentRow(rowKey, option = { silent: false }) {
|
|
1581
1583
|
if (!dataSourceCopy.value.length)
|
|
1582
1584
|
return;
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
+
const row = dataSourceCopy.value.find((it) => rowKeyGen(it) === rowKey);
|
|
1586
|
+
if (!row) {
|
|
1587
|
+
console.warn("setCurrentRow failed.rowKey:", rowKey);
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
currentRow.value = row;
|
|
1591
|
+
currentRowKey.value = rowKey;
|
|
1585
1592
|
if (!option.silent) {
|
|
1586
1593
|
emits(
|
|
1587
1594
|
"current-change",
|
|
1588
1595
|
/** no Event */
|
|
1589
1596
|
null,
|
|
1590
1597
|
currentRow.value,
|
|
1591
|
-
{ select:
|
|
1598
|
+
{ select: true }
|
|
1592
1599
|
);
|
|
1593
1600
|
}
|
|
1594
1601
|
}
|
|
@@ -1710,11 +1717,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1710
1717
|
}, [
|
|
1711
1718
|
unref(virtualX_on) ? (openBlock(), createElementBlock("th", {
|
|
1712
1719
|
key: 0,
|
|
1713
|
-
class: "
|
|
1714
|
-
style: normalizeStyle({
|
|
1715
|
-
minWidth: unref(virtualScrollX).offsetLeft + "px",
|
|
1716
|
-
width: unref(virtualScrollX).offsetLeft + "px"
|
|
1717
|
-
})
|
|
1720
|
+
class: "vt-x-left",
|
|
1721
|
+
style: normalizeStyle(`min-width:${unref(virtualScrollX).offsetLeft}px;width:${unref(virtualScrollX).offsetLeft}px`)
|
|
1718
1722
|
}, null, 4)) : createCommentVNode("", true),
|
|
1719
1723
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtualX_on) && rowIndex === tableHeaders.value.length - 1 ? unref(virtualX_columnPart) : row, (col, colIndex) => {
|
|
1720
1724
|
return openBlock(), createElementBlock("th", {
|
|
@@ -1742,65 +1746,66 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1742
1746
|
onDragover: _cache[2] || (_cache[2] = //@ts-ignore
|
|
1743
1747
|
(...args) => unref(onThDragOver) && unref(onThDragOver)(...args))
|
|
1744
1748
|
}, [
|
|
1745
|
-
createElementVNode("div",
|
|
1749
|
+
createElementVNode("div", {
|
|
1750
|
+
class: "table-header-cell-wrapper",
|
|
1751
|
+
style: normalizeStyle(`--row-span:${unref(virtualX_on) ? 1 : col.rowSpan}`)
|
|
1752
|
+
}, [
|
|
1746
1753
|
col.customHeaderCell ? (openBlock(), createBlock(resolveDynamicComponent(col.customHeaderCell), {
|
|
1747
1754
|
key: 0,
|
|
1748
1755
|
col,
|
|
1749
1756
|
colIndex,
|
|
1750
1757
|
rowIndex
|
|
1751
|
-
}, null, 8, ["col", "colIndex", "rowIndex"])) : col.type === "seq" ? (openBlock(), createElementBlock("span",
|
|
1758
|
+
}, null, 8, ["col", "colIndex", "rowIndex"])) : col.type === "seq" ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(col.title), 1)) : renderSlot(_ctx.$slots, "tableHeader", {
|
|
1752
1759
|
key: 2,
|
|
1753
1760
|
col
|
|
1754
1761
|
}, () => [
|
|
1755
|
-
createElementVNode("span",
|
|
1762
|
+
createElementVNode("span", _hoisted_3, toDisplayString(col.title), 1)
|
|
1756
1763
|
]),
|
|
1757
|
-
col.sorter ? (openBlock(), createElementBlock("span",
|
|
1764
|
+
col.sorter ? (openBlock(), createElementBlock("span", _hoisted_4, _hoisted_6)) : createCommentVNode("", true),
|
|
1758
1765
|
_ctx.colResizable && colIndex > 0 ? (openBlock(), createElementBlock("div", {
|
|
1759
1766
|
key: 4,
|
|
1760
1767
|
class: "table-header-resizer left",
|
|
1761
1768
|
onMousedown: (e) => unref(onThResizeMouseDown)(e, col, true)
|
|
1762
|
-
}, null, 40,
|
|
1769
|
+
}, null, 40, _hoisted_7)) : createCommentVNode("", true),
|
|
1763
1770
|
_ctx.colResizable ? (openBlock(), createElementBlock("div", {
|
|
1764
1771
|
key: 5,
|
|
1765
1772
|
class: "table-header-resizer right",
|
|
1766
1773
|
onMousedown: (e) => unref(onThResizeMouseDown)(e, col)
|
|
1767
|
-
}, null, 40,
|
|
1768
|
-
])
|
|
1774
|
+
}, null, 40, _hoisted_8)) : createCommentVNode("", true)
|
|
1775
|
+
], 4)
|
|
1769
1776
|
], 46, _hoisted_1);
|
|
1770
1777
|
}), 128)),
|
|
1771
1778
|
unref(virtualX_on) ? (openBlock(), createElementBlock("th", {
|
|
1772
1779
|
key: 1,
|
|
1773
|
-
class: "
|
|
1774
|
-
style: normalizeStyle({
|
|
1775
|
-
minWidth: unref(virtualX_offsetRight) + "px",
|
|
1776
|
-
width: unref(virtualX_offsetRight) + "px"
|
|
1777
|
-
})
|
|
1780
|
+
class: "vt-x-right",
|
|
1781
|
+
style: normalizeStyle(`min-width:${unref(virtualX_offsetRight)}px;width:${unref(virtualX_offsetRight)}px`)
|
|
1778
1782
|
}, null, 4)) : createCommentVNode("", true)
|
|
1779
1783
|
], 32);
|
|
1780
1784
|
}), 128))
|
|
1781
1785
|
], 512)) : createCommentVNode("", true),
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1786
|
+
createElementVNode("tbody", {
|
|
1787
|
+
class: normalizeClass(["stk-tbody-main", unref(virtual_on) ? "vt-on" : "vt-off"])
|
|
1788
|
+
}, [
|
|
1789
|
+
unref(virtual_on) ? (openBlock(), createElementBlock("tr", {
|
|
1790
|
+
key: 0,
|
|
1791
|
+
style: normalizeStyle(`height:${unref(virtualScroll).offsetTop}px`),
|
|
1785
1792
|
class: "padding-top-tr"
|
|
1786
1793
|
}, [
|
|
1787
|
-
unref(virtualX_on) && _ctx.fixedMode && _ctx.headless ? (openBlock(), createElementBlock("td",
|
|
1794
|
+
unref(virtualX_on) && _ctx.fixedMode && _ctx.headless ? (openBlock(), createElementBlock("td", _hoisted_9)) : createCommentVNode("", true),
|
|
1788
1795
|
_ctx.fixedMode && _ctx.headless ? (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(unref(virtualX_columnPart), (col) => {
|
|
1789
1796
|
return openBlock(), createElementBlock("td", {
|
|
1790
1797
|
key: col.dataIndex,
|
|
1791
1798
|
style: normalizeStyle(cellStyleMap.value[unref(TagType).TD].get(colKeyGen.value(col)))
|
|
1792
1799
|
}, null, 4);
|
|
1793
1800
|
}), 128)) : createCommentVNode("", true)
|
|
1794
|
-
], 4)
|
|
1795
|
-
])) : createCommentVNode("", true),
|
|
1796
|
-
createElementVNode("tbody", _hoisted_12, [
|
|
1801
|
+
], 4)) : createCommentVNode("", true),
|
|
1797
1802
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtual_dataSourcePart), (row, rowIndex) => {
|
|
1798
1803
|
return openBlock(), createElementBlock("tr", {
|
|
1799
1804
|
id: unref(stkTableId) + "-" + (_ctx.rowKey ? rowKeyGen(row) : rowIndex),
|
|
1800
1805
|
key: _ctx.rowKey ? rowKeyGen(row) : rowIndex,
|
|
1801
1806
|
"data-row-key": _ctx.rowKey ? rowKeyGen(row) : rowIndex,
|
|
1802
1807
|
class: normalizeClass({
|
|
1803
|
-
active: _ctx.rowKey ? rowKeyGen(row) ===
|
|
1808
|
+
active: _ctx.rowKey ? rowKeyGen(row) === currentRowKey.value : row === currentRow.value,
|
|
1804
1809
|
hover: props.showTrHoverClass && (_ctx.rowKey ? rowKeyGen(row) === currentHoverRowKey.value : row === currentHoverRowKey.value),
|
|
1805
1810
|
[_ctx.rowClassName(row, rowIndex)]: true
|
|
1806
1811
|
}),
|
|
@@ -1809,7 +1814,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1809
1814
|
onContextmenu: (e) => onRowMenu(e, row),
|
|
1810
1815
|
onMouseover: (e) => onTrMouseOver(e, row)
|
|
1811
1816
|
}, [
|
|
1812
|
-
unref(virtualX_on) ? (openBlock(), createElementBlock("td",
|
|
1817
|
+
unref(virtualX_on) ? (openBlock(), createElementBlock("td", _hoisted_11)) : createCommentVNode("", true),
|
|
1813
1818
|
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(virtualX_columnPart), (col, colIndex) => {
|
|
1814
1819
|
return openBlock(), createElementBlock("td", {
|
|
1815
1820
|
key: col.dataIndex,
|
|
@@ -1838,17 +1843,16 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1838
1843
|
], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
1839
1844
|
createTextVNode(toDisplayString((row == null ? void 0 : row[col.dataIndex]) ?? getEmptyCellText.value(col, row)), 1)
|
|
1840
1845
|
], 64))
|
|
1841
|
-
], 8,
|
|
1842
|
-
], 46,
|
|
1846
|
+
], 8, _hoisted_13))
|
|
1847
|
+
], 46, _hoisted_12);
|
|
1843
1848
|
}), 128))
|
|
1844
|
-
], 42,
|
|
1845
|
-
}), 128))
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
])) : createCommentVNode("", true)
|
|
1849
|
+
], 42, _hoisted_10);
|
|
1850
|
+
}), 128)),
|
|
1851
|
+
unref(virtual_on) ? (openBlock(), createElementBlock("tr", {
|
|
1852
|
+
key: 1,
|
|
1853
|
+
style: normalizeStyle(`height: ${unref(virtual_offsetBottom)}px`)
|
|
1854
|
+
}, null, 4)) : createCommentVNode("", true)
|
|
1855
|
+
], 2)
|
|
1852
1856
|
], 6),
|
|
1853
1857
|
(!dataSourceCopy.value || !dataSourceCopy.value.length) && _ctx.showNoData ? (openBlock(), createElementBlock("div", {
|
|
1854
1858
|
key: 1,
|
package/lib/style.css
CHANGED
|
@@ -91,7 +91,10 @@
|
|
|
91
91
|
.stk-table.border-body-v tbody{
|
|
92
92
|
--bg-border-bottom:linear-gradient(transparent, transparent);
|
|
93
93
|
}
|
|
94
|
-
.stk-table.stripe tbody tr:nth-child(
|
|
94
|
+
.stk-table.stripe .stk-tbody-main.vt-on tr:nth-child(odd){
|
|
95
|
+
background-color:var(--stripe-bgc);
|
|
96
|
+
}
|
|
97
|
+
.stk-table.stripe .stk-tbody-main.vt-off tr:nth-child(even){
|
|
95
98
|
background-color:var(--stripe-bgc);
|
|
96
99
|
}
|
|
97
100
|
.stk-table.row-hover tbody tr:hover{
|
|
@@ -120,7 +123,7 @@
|
|
|
120
123
|
}
|
|
121
124
|
.stk-table.virtual .table-header-cell-wrapper{
|
|
122
125
|
overflow:hidden;
|
|
123
|
-
max-height:var(--header-row-height);
|
|
126
|
+
max-height:calc(var(--header-row-height) * var(--row-span));
|
|
124
127
|
}
|
|
125
128
|
.stk-table.virtual tbody td{
|
|
126
129
|
height:var(--row-height);
|
|
@@ -187,8 +190,8 @@
|
|
|
187
190
|
background-color:var(--td-bgc);
|
|
188
191
|
height:var(--row-height);
|
|
189
192
|
}
|
|
190
|
-
.stk-table .
|
|
191
|
-
.stk-table .
|
|
193
|
+
.stk-table .vt-x-left,
|
|
194
|
+
.stk-table .vt-x-right{
|
|
192
195
|
padding:0;
|
|
193
196
|
background:none;
|
|
194
197
|
pointer-events:none;
|
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "stk-table-vue",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "Simple realtime virtual table for vue3 and vue2.7",
|
|
5
|
-
"main": "./lib/stk-table-vue.js",
|
|
6
|
-
"types": "./lib/src/StkTable/index.d.ts",
|
|
7
|
-
"packageManager": "pnpm@8.14.3",
|
|
8
|
-
"directories": {
|
|
9
|
-
"test": "test"
|
|
10
|
-
},
|
|
11
|
-
"type": "module",
|
|
12
|
-
"scripts": {
|
|
13
|
-
"dev": "vite",
|
|
14
|
-
"build": "vite build",
|
|
15
|
-
"test": "vitest"
|
|
16
|
-
},
|
|
17
|
-
"keywords": [
|
|
18
|
-
"virtual table",
|
|
19
|
-
"vue",
|
|
20
|
-
"vue2",
|
|
21
|
-
"vue3",
|
|
22
|
-
"highlight",
|
|
23
|
-
"sticky",
|
|
24
|
-
"virtual",
|
|
25
|
-
"table",
|
|
26
|
-
"list"
|
|
27
|
-
],
|
|
28
|
-
"files": [
|
|
29
|
-
"lib",
|
|
30
|
-
"src"
|
|
31
|
-
],
|
|
32
|
-
"author": "japlus",
|
|
33
|
-
"repository": {
|
|
34
|
-
"type": "git",
|
|
35
|
-
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
36
|
-
},
|
|
37
|
-
"license": "MIT",
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"@types/d3-interpolate": "^3.0.4",
|
|
40
|
-
"@types/node": "^20.12.10",
|
|
41
|
-
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
42
|
-
"@typescript-eslint/parser": "^7.7.0",
|
|
43
|
-
"@vitejs/plugin-vue": "^5.0.4",
|
|
44
|
-
"@vue/test-utils": "2.4.4",
|
|
45
|
-
"eslint": "^8.57.0",
|
|
46
|
-
"eslint-config-prettier": "^9.1.0",
|
|
47
|
-
"eslint-plugin-html": "^8.1.0",
|
|
48
|
-
"eslint-plugin-prettier": "^5.1.3",
|
|
49
|
-
"eslint-plugin-vue": "^9.25.0",
|
|
50
|
-
"happy-dom": "^12.10.3",
|
|
51
|
-
"less": "^4.2.0",
|
|
52
|
-
"postcss-discard-comments": "^6.0.2",
|
|
53
|
-
"postcss-preset-env": "^9.5.11",
|
|
54
|
-
"prettier": "^3.2.5",
|
|
55
|
-
"typescript": "^5.4.5",
|
|
56
|
-
"vite": "^5.2.11",
|
|
57
|
-
"vite-plugin-dts": "^3.9.1",
|
|
58
|
-
"vitest": "^1.6.0",
|
|
59
|
-
"vue": "^3.4.26",
|
|
60
|
-
"vue-eslint-parser": "^9.4.2"
|
|
61
|
-
},
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"d3-interpolate": "^3.0.1"
|
|
64
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "stk-table-vue",
|
|
3
|
+
"version": "0.4.8",
|
|
4
|
+
"description": "Simple realtime virtual table for vue3 and vue2.7",
|
|
5
|
+
"main": "./lib/stk-table-vue.js",
|
|
6
|
+
"types": "./lib/src/StkTable/index.d.ts",
|
|
7
|
+
"packageManager": "pnpm@8.14.3",
|
|
8
|
+
"directories": {
|
|
9
|
+
"test": "test"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "vite",
|
|
14
|
+
"build": "vite build",
|
|
15
|
+
"test": "vitest"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"virtual table",
|
|
19
|
+
"vue",
|
|
20
|
+
"vue2",
|
|
21
|
+
"vue3",
|
|
22
|
+
"highlight",
|
|
23
|
+
"sticky",
|
|
24
|
+
"virtual",
|
|
25
|
+
"table",
|
|
26
|
+
"list"
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
"lib",
|
|
30
|
+
"src"
|
|
31
|
+
],
|
|
32
|
+
"author": "japlus",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/ja-plus/stk-table-vue"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/d3-interpolate": "^3.0.4",
|
|
40
|
+
"@types/node": "^20.12.10",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
|
42
|
+
"@typescript-eslint/parser": "^7.7.0",
|
|
43
|
+
"@vitejs/plugin-vue": "^5.0.4",
|
|
44
|
+
"@vue/test-utils": "2.4.4",
|
|
45
|
+
"eslint": "^8.57.0",
|
|
46
|
+
"eslint-config-prettier": "^9.1.0",
|
|
47
|
+
"eslint-plugin-html": "^8.1.0",
|
|
48
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
49
|
+
"eslint-plugin-vue": "^9.25.0",
|
|
50
|
+
"happy-dom": "^12.10.3",
|
|
51
|
+
"less": "^4.2.0",
|
|
52
|
+
"postcss-discard-comments": "^6.0.2",
|
|
53
|
+
"postcss-preset-env": "^9.5.11",
|
|
54
|
+
"prettier": "^3.2.5",
|
|
55
|
+
"typescript": "^5.4.5",
|
|
56
|
+
"vite": "^5.2.11",
|
|
57
|
+
"vite-plugin-dts": "^3.9.1",
|
|
58
|
+
"vitest": "^1.6.0",
|
|
59
|
+
"vue": "^3.4.26",
|
|
60
|
+
"vue-eslint-parser": "^9.4.2"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"d3-interpolate": "^3.0.1"
|
|
64
|
+
}
|
|
65
65
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<!-- eslint-disable vue/attribute-hyphenation -->
|
|
1
2
|
<template>
|
|
2
3
|
<div
|
|
3
4
|
ref="tableContainerRef"
|
|
@@ -52,11 +53,8 @@
|
|
|
52
53
|
<!-- 这个th用于横向虚拟滚动表格左边距,width、maxWidth 用于兼容低版本浏览器 -->
|
|
53
54
|
<th
|
|
54
55
|
v-if="virtualX_on"
|
|
55
|
-
class="
|
|
56
|
-
:style="{
|
|
57
|
-
minWidth: virtualScrollX.offsetLeft + 'px',
|
|
58
|
-
width: virtualScrollX.offsetLeft + 'px',
|
|
59
|
-
}"
|
|
56
|
+
class="vt-x-left"
|
|
57
|
+
:style="`min-width:${virtualScrollX.offsetLeft}px;width:${virtualScrollX.offsetLeft}px`"
|
|
60
58
|
></th>
|
|
61
59
|
<!-- v for中最后一行才用 切割。TODO:不支持多级表头虚拟横向滚动 -->
|
|
62
60
|
<th
|
|
@@ -84,7 +82,7 @@
|
|
|
84
82
|
@drop="onThDrop"
|
|
85
83
|
@dragover="onThDragOver"
|
|
86
84
|
>
|
|
87
|
-
<div class="table-header-cell-wrapper">
|
|
85
|
+
<div class="table-header-cell-wrapper" :style="`--row-span:${virtualX_on ? 1 : col.rowSpan}`">
|
|
88
86
|
<component :is="col.customHeaderCell" v-if="col.customHeaderCell" :col="col" :colIndex="colIndex" :rowIndex="rowIndex" />
|
|
89
87
|
<template v-else-if="col.type === 'seq'">
|
|
90
88
|
<span class="table-header-title">{{ col.title }}</span>
|
|
@@ -116,46 +114,28 @@
|
|
|
116
114
|
</div>
|
|
117
115
|
</th>
|
|
118
116
|
<!-- 这个th用于横向虚拟滚动表格右边距 width、maxWidth 用于兼容低版本浏览器-->
|
|
119
|
-
<th
|
|
120
|
-
v-if="virtualX_on"
|
|
121
|
-
class="virtual-x-right"
|
|
122
|
-
:style="{
|
|
123
|
-
minWidth: virtualX_offsetRight + 'px',
|
|
124
|
-
width: virtualX_offsetRight + 'px',
|
|
125
|
-
}"
|
|
126
|
-
></th>
|
|
117
|
+
<th v-if="virtualX_on" class="vt-x-right" :style="`min-width:${virtualX_offsetRight}px;width:${virtualX_offsetRight}px`"></th>
|
|
127
118
|
</tr>
|
|
128
119
|
</thead>
|
|
129
120
|
|
|
130
121
|
<!-- 用于虚拟滚动表格内容定位 @deprecated 有兼容问题-->
|
|
131
|
-
<!-- <tbody v-if="virtual_on" :style="{ height: `${virtualScroll.offsetTop}px` }">
|
|
132
|
-
<!==这个tr兼容火狐==>
|
|
133
|
-
<tr></tr>
|
|
134
|
-
</tbody> -->
|
|
135
|
-
<!-- <td
|
|
136
|
-
v-for="col in virtualX_on ? virtualX_columnPart : tableHeaderLast"
|
|
137
|
-
:key="col.dataIndex"
|
|
138
|
-
class="perch-td top"
|
|
139
|
-
></td> -->
|
|
122
|
+
<!-- <tbody v-if="virtual_on" :style="{ height: `${virtualScroll.offsetTop}px` }"></tbody> -->
|
|
140
123
|
<!-- <tbody :style="{ transform: `translateY(${virtualScroll.offsetTop}px)` }"> -->
|
|
141
|
-
<tbody
|
|
142
|
-
|
|
143
|
-
<tr :style="{ height: `${virtualScroll.offsetTop}px` }" class="padding-top-tr">
|
|
124
|
+
<tbody class="stk-tbody-main" :class="virtual_on ? 'vt-on' : 'vt-off'">
|
|
125
|
+
<tr v-if="virtual_on" :style="`height:${virtualScroll.offsetTop}px`" class="padding-top-tr">
|
|
144
126
|
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
145
|
-
<td v-if="virtualX_on && fixedMode && headless" class="
|
|
127
|
+
<td v-if="virtualX_on && fixedMode && headless" class="vt-x-left"></td>
|
|
146
128
|
<template v-if="fixedMode && headless">
|
|
147
129
|
<td v-for="col in virtualX_columnPart" :key="col.dataIndex" :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"></td>
|
|
148
130
|
</template>
|
|
149
131
|
</tr>
|
|
150
|
-
</tbody>
|
|
151
|
-
<tbody class="stk-tbody-main">
|
|
152
132
|
<tr
|
|
153
133
|
v-for="(row, rowIndex) in virtual_dataSourcePart"
|
|
154
134
|
:id="stkTableId + '-' + (rowKey ? rowKeyGen(row) : rowIndex)"
|
|
155
135
|
:key="rowKey ? rowKeyGen(row) : rowIndex"
|
|
156
136
|
:data-row-key="rowKey ? rowKeyGen(row) : rowIndex"
|
|
157
137
|
:class="{
|
|
158
|
-
active: rowKey ? rowKeyGen(row) ===
|
|
138
|
+
active: rowKey ? rowKeyGen(row) === currentRowKey : row === currentRow,
|
|
159
139
|
hover: props.showTrHoverClass && (rowKey ? rowKeyGen(row) === currentHoverRowKey : row === currentHoverRowKey),
|
|
160
140
|
[rowClassName(row, rowIndex)]: true,
|
|
161
141
|
}"
|
|
@@ -165,7 +145,7 @@
|
|
|
165
145
|
@mouseover="e => onTrMouseOver(e, row)"
|
|
166
146
|
>
|
|
167
147
|
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
168
|
-
<td v-if="virtualX_on" class="
|
|
148
|
+
<td v-if="virtualX_on" class="vt-x-left"></td>
|
|
169
149
|
<td
|
|
170
150
|
v-for="(col, colIndex) in virtualX_columnPart"
|
|
171
151
|
:key="col.dataIndex"
|
|
@@ -196,9 +176,7 @@
|
|
|
196
176
|
</div>
|
|
197
177
|
</td>
|
|
198
178
|
</tr>
|
|
199
|
-
|
|
200
|
-
<tbody v-if="virtual_on" class="virtual-bottom">
|
|
201
|
-
<tr :style="{ height: `${virtual_offsetBottom}px` }"></tr>
|
|
179
|
+
<tr v-if="virtual_on" :style="`height: ${virtual_offsetBottom}px`"></tr>
|
|
202
180
|
</tbody>
|
|
203
181
|
</table>
|
|
204
182
|
<div v-if="(!dataSourceCopy || !dataSourceCopy.length) && showNoData" class="stk-table-no-data" :class="{ 'no-data-full': noDataFull }">
|
|
@@ -228,7 +206,7 @@ import { useVirtualScroll } from './useVirtualScroll';
|
|
|
228
206
|
import { createStkTableId, getCalculatedColWidth, getColWidth, howDeepTheHeader, tableSort, transformWidthToStr } from './utils/index';
|
|
229
207
|
|
|
230
208
|
/** Generic stands for DataType */
|
|
231
|
-
type DT =
|
|
209
|
+
type DT = any;
|
|
232
210
|
/** 自己生成实例id */
|
|
233
211
|
const stkTableId = createStkTableId();
|
|
234
212
|
/**
|
|
@@ -633,6 +611,14 @@ watch(
|
|
|
633
611
|
});
|
|
634
612
|
},
|
|
635
613
|
);
|
|
614
|
+
watch(
|
|
615
|
+
() => props.virtual,
|
|
616
|
+
() => {
|
|
617
|
+
nextTick(() => {
|
|
618
|
+
initVirtualScrollY();
|
|
619
|
+
});
|
|
620
|
+
},
|
|
621
|
+
);
|
|
636
622
|
watch(
|
|
637
623
|
() => props.virtualX,
|
|
638
624
|
() => {
|
|
@@ -1036,10 +1022,15 @@ function onTrMouseOver(_e: MouseEvent, row: DT) {
|
|
|
1036
1022
|
*/
|
|
1037
1023
|
function setCurrentRow(rowKey: string, option = { silent: false }) {
|
|
1038
1024
|
if (!dataSourceCopy.value.length) return;
|
|
1039
|
-
|
|
1040
|
-
|
|
1025
|
+
const row = dataSourceCopy.value.find(it => rowKeyGen(it) === rowKey);
|
|
1026
|
+
if (!row) {
|
|
1027
|
+
console.warn('setCurrentRow failed.rowKey:', rowKey);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
currentRow.value = row;
|
|
1031
|
+
currentRowKey.value = rowKey;
|
|
1041
1032
|
if (!option.silent) {
|
|
1042
|
-
emits('current-change', /** no Event */ null, currentRow.value, { select:
|
|
1033
|
+
emits('current-change', /** no Event */ null, currentRow.value, { select: true });
|
|
1043
1034
|
}
|
|
1044
1035
|
}
|
|
1045
1036
|
|
package/src/StkTable/style.less
CHANGED
|
@@ -134,9 +134,13 @@
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
/* 斑马纹*/
|
|
137
|
-
&.stripe {
|
|
137
|
+
&.stripe .stk-tbody-main {
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
&.vt-on tr:nth-child(odd) {
|
|
140
|
+
background-color: var(--stripe-bgc);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&.vt-off tr:nth-child(even) {
|
|
140
144
|
background-color: var(--stripe-bgc);
|
|
141
145
|
}
|
|
142
146
|
}
|
|
@@ -183,7 +187,7 @@
|
|
|
183
187
|
/* 为不影响布局,表头行高要定死*/
|
|
184
188
|
.table-header-cell-wrapper {
|
|
185
189
|
overflow: hidden;
|
|
186
|
-
max-height: var(--header-row-height);
|
|
190
|
+
max-height: calc(var(--header-row-height) * var(--row-span));
|
|
187
191
|
}
|
|
188
192
|
|
|
189
193
|
tbody td {
|
|
@@ -279,8 +283,8 @@
|
|
|
279
283
|
}
|
|
280
284
|
|
|
281
285
|
|
|
282
|
-
.
|
|
283
|
-
.
|
|
286
|
+
.vt-x-left,
|
|
287
|
+
.vt-x-right {
|
|
284
288
|
padding: 0;
|
|
285
289
|
background: none;
|
|
286
290
|
pointer-events: none;
|
|
@@ -37,9 +37,6 @@ export function useFixedStyle<DT extends Record<string, any>>({
|
|
|
37
37
|
|
|
38
38
|
const style: CSSProperties = {};
|
|
39
39
|
|
|
40
|
-
const { scrollLeft, scrollWidth, offsetLeft, containerWidth } = virtualScrollX.value;
|
|
41
|
-
const scrollRight = scrollWidth - containerWidth - scrollLeft;
|
|
42
|
-
|
|
43
40
|
const isFixedLeft = fixed === 'left';
|
|
44
41
|
if (tagType === TagType.TH) {
|
|
45
42
|
// TH
|
|
@@ -50,6 +47,9 @@ export function useFixedStyle<DT extends Record<string, any>>({
|
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
|
|
50
|
+
const { scrollLeft, scrollWidth, offsetLeft, containerWidth } = virtualScrollX.value;
|
|
51
|
+
const scrollRight = scrollWidth - containerWidth - scrollLeft;
|
|
52
|
+
|
|
53
53
|
if (fixed === 'left' || fixed === 'right') {
|
|
54
54
|
if (isRelativeMode.value) {
|
|
55
55
|
if (isFixedLeft) {
|
|
@@ -3,7 +3,16 @@ import { StkTableColumn } from './types';
|
|
|
3
3
|
import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
4
4
|
|
|
5
5
|
/** 翻页按键 */
|
|
6
|
-
|
|
6
|
+
enum ScrollCodes {
|
|
7
|
+
ArrowUp = 'ArrowUp',
|
|
8
|
+
ArrowRight = 'ArrowRight',
|
|
9
|
+
ArrowDown = 'ArrowDown',
|
|
10
|
+
ArrowLeft = 'ArrowLeft',
|
|
11
|
+
PageUp = 'PageUp',
|
|
12
|
+
PageDown = 'PageDown',
|
|
13
|
+
}
|
|
14
|
+
/** 所有翻页按键数组 */
|
|
15
|
+
const ScrollCodesValues = Object.values(ScrollCodes);
|
|
7
16
|
|
|
8
17
|
type Options<DT extends Record<string, any>> = {
|
|
9
18
|
props: any;
|
|
@@ -52,7 +61,8 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
|
|
|
52
61
|
|
|
53
62
|
/** 键盘按下事件 */
|
|
54
63
|
function handleKeydown(e: KeyboardEvent) {
|
|
55
|
-
if (!
|
|
64
|
+
if (!virtual_on.value) return; // 非虚拟滚动使用浏览器默认滚动
|
|
65
|
+
if (!ScrollCodesValues.includes(e.code as any)) return;
|
|
56
66
|
if (!isMouseOver) return; // 不悬浮还是要触发键盘事件的
|
|
57
67
|
e.preventDefault(); // 不触发键盘默认的箭头事件
|
|
58
68
|
|
|
@@ -65,17 +75,17 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
|
|
|
65
75
|
/** 表体的page */
|
|
66
76
|
const bodyPageSize = Math.floor((containerHeight - headerHeight) / rowHeight);
|
|
67
77
|
|
|
68
|
-
if (e.code ===
|
|
78
|
+
if (e.code === ScrollCodes.ArrowUp) {
|
|
69
79
|
scrollTo(scrollTop - rowHeight, null);
|
|
70
|
-
} else if (e.code ===
|
|
80
|
+
} else if (e.code === ScrollCodes.ArrowRight) {
|
|
71
81
|
scrollTo(null, scrollLeft + rowHeight);
|
|
72
|
-
} else if (e.code ===
|
|
82
|
+
} else if (e.code === ScrollCodes.ArrowDown) {
|
|
73
83
|
scrollTo(scrollTop + rowHeight, null);
|
|
74
|
-
} else if (e.code ===
|
|
84
|
+
} else if (e.code === ScrollCodes.ArrowLeft) {
|
|
75
85
|
scrollTo(null, scrollLeft - rowHeight);
|
|
76
|
-
} else if (e.code ===
|
|
86
|
+
} else if (e.code === ScrollCodes.PageUp) {
|
|
77
87
|
scrollTo(scrollTop - rowHeight * bodyPageSize + headerHeight, null);
|
|
78
|
-
} else if (e.code ===
|
|
88
|
+
} else if (e.code === ScrollCodes.PageDown) {
|
|
79
89
|
scrollTo(scrollTop + rowHeight * bodyPageSize - headerHeight, null);
|
|
80
90
|
}
|
|
81
91
|
}
|
|
@@ -163,6 +163,15 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
163
163
|
// return theadRef.value?.offsetHeight || 0;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
/**
|
|
167
|
+
* 初始化虚拟滚动参数
|
|
168
|
+
* @param {number} [height] 虚拟滚动的高度
|
|
169
|
+
*/
|
|
170
|
+
function initVirtualScroll(height?: number) {
|
|
171
|
+
initVirtualScrollY(height);
|
|
172
|
+
initVirtualScrollX();
|
|
173
|
+
}
|
|
174
|
+
|
|
166
175
|
/**
|
|
167
176
|
* 初始化Y虚拟滚动参数
|
|
168
177
|
* @param {number} [height] 虚拟滚动的高度
|
|
@@ -184,7 +193,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
184
193
|
tableHeaderHeight.value = headerHeight;
|
|
185
194
|
if (!headless) {
|
|
186
195
|
/** 表头高度占几行表体高度数 */
|
|
187
|
-
const headerToBodyRowHeightCount = Math.floor(headerHeight
|
|
196
|
+
const headerToBodyRowHeightCount = Math.floor(headerHeight / rowHeight);
|
|
188
197
|
pageSize -= headerToBodyRowHeightCount; //减去表头行数
|
|
189
198
|
}
|
|
190
199
|
/** 最大的scrollTop */
|
|
@@ -203,20 +212,12 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
203
212
|
virtualScrollX.value.scrollWidth = scrollWidth || DEFAULT_TABLE_WIDTH;
|
|
204
213
|
updateVirtualScrollX(scrollLeft);
|
|
205
214
|
}
|
|
206
|
-
/**
|
|
207
|
-
* 初始化虚拟滚动参数
|
|
208
|
-
* @param {number} [height] 虚拟滚动的高度
|
|
209
|
-
*/
|
|
210
|
-
function initVirtualScroll(height?: number) {
|
|
211
|
-
initVirtualScrollY(height);
|
|
212
|
-
initVirtualScrollX();
|
|
213
|
-
}
|
|
214
215
|
|
|
215
216
|
let vue2ScrollYTimeout: null | number = null;
|
|
216
217
|
|
|
217
218
|
/** 通过滚动条位置,计算虚拟滚动的参数 */
|
|
218
219
|
function updateVirtualScrollY(sTop = 0) {
|
|
219
|
-
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex } = virtualScroll.value;
|
|
220
|
+
const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex, endIndex: oldEndIndex } = virtualScroll.value;
|
|
220
221
|
// 先更新滚动条位置记录,其他地方有依赖。(stripe 时ArrowUp/Down滚动依赖)
|
|
221
222
|
virtualScroll.value.scrollTop = sTop;
|
|
222
223
|
|
|
@@ -226,22 +227,18 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
let startIndex = Math.floor(sTop / rowHeight);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
230
|
+
let endIndex = startIndex + pageSize;
|
|
231
|
+
|
|
232
232
|
if (props.stripe && startIndex !== 0) {
|
|
233
|
-
const scrollRows = Math.abs(oldStartIndex - startIndex);
|
|
234
233
|
// 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
|
|
235
|
-
if (
|
|
234
|
+
if (startIndex % 2) {
|
|
236
235
|
startIndex -= 1; // 奇数-1变成偶数
|
|
237
236
|
}
|
|
238
237
|
}
|
|
239
|
-
let endIndex = startIndex + pageSize;
|
|
240
|
-
if (props.stripe) {
|
|
241
|
-
endIndex += 1; // 斑马纹下多渲染一些
|
|
242
|
-
}
|
|
243
238
|
|
|
244
|
-
|
|
239
|
+
startIndex = Math.max(0, startIndex);
|
|
240
|
+
|
|
241
|
+
// 溢出修正
|
|
245
242
|
endIndex = Math.min(endIndex, dataSourceCopy.value.length);
|
|
246
243
|
|
|
247
244
|
if (startIndex >= endIndex) {
|
|
@@ -253,6 +250,11 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
253
250
|
window.clearTimeout(vue2ScrollYTimeout);
|
|
254
251
|
}
|
|
255
252
|
|
|
253
|
+
if (oldStartIndex === startIndex && oldEndIndex === endIndex) {
|
|
254
|
+
// 没有变化,不需要更新
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
256
258
|
const offsetTop = startIndex * rowHeight; // startIndex之前的高度
|
|
257
259
|
|
|
258
260
|
/**
|
|
@@ -260,11 +262,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
|
|
|
260
262
|
*/
|
|
261
263
|
if (!props.optimizeVue2Scroll || sTop <= scrollTop || Math.abs(oldStartIndex - startIndex) >= pageSize) {
|
|
262
264
|
// 向上滚动
|
|
263
|
-
Object.assign(virtualScroll.value, {
|
|
264
|
-
startIndex,
|
|
265
|
-
endIndex,
|
|
266
|
-
offsetTop,
|
|
267
|
-
});
|
|
265
|
+
Object.assign(virtualScroll.value, { startIndex, endIndex, offsetTop });
|
|
268
266
|
} else {
|
|
269
267
|
// vue2向下滚动优化
|
|
270
268
|
virtualScroll.value.endIndex = endIndex;
|