stk-table-vue 0.11.4 → 0.11.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/lib/index-t5SJ6KNv.js +1 -1
- package/lib/src/StkTable/features/useAreaSelection.d.ts +2 -1
- package/lib/src/StkTable/types/index.d.ts +1 -0
- package/lib/src/StkTable/useKeyboardArrowScroll.d.ts +2 -2
- package/lib/src/StkTable/useVirtualScroll.d.ts +1 -1
- package/lib/stk-table-vue.js +56 -48
- package/lib/style.css +1 -1
- package/package.json +1 -1
- package/src/StkTable/StkTable.vue +34 -28
- package/src/StkTable/features/useAreaSelection.ts +21 -10
- package/src/StkTable/registerFeature.ts +2 -1
- package/src/StkTable/types/index.ts +1 -0
- package/src/StkTable/useKeyboardArrowScroll.ts +3 -3
- package/src/StkTable/useVirtualScroll.ts +8 -8
package/lib/index-t5SJ6KNv.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Ref, ShallowRef } from 'vue';
|
|
2
|
-
import { CellKeyGen, ColKeyGen, StkTableColumn, UniqKey } from '../types';
|
|
2
|
+
import { AreaSelectionConfig, CellKeyGen, ColKeyGen, StkTableColumn, UniqKey } from '../types';
|
|
3
3
|
import { VirtualScrollStore, VirtualScrollXStore } from '../useVirtualScroll';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -8,6 +8,7 @@ import { VirtualScrollStore, VirtualScrollXStore } from '../useVirtualScroll';
|
|
|
8
8
|
* en: Cell area selection feature with mouse drag, keyboard navigation, copy-paste, etc.
|
|
9
9
|
*/
|
|
10
10
|
export declare function useAreaSelection<DT extends Record<string, any>>(props: any, emits: any, tableContainerRef: Ref<HTMLDivElement | undefined>, dataSourceCopy: ShallowRef<DT[]>, tableHeaderLast: ShallowRef<StkTableColumn<DT>[]>, colKeyGen: ColKeyGen, cellKeyGen: CellKeyGen, scrollTo: (top: number | null, left: number | null) => void, virtualScroll: Ref<VirtualScrollStore>, virtualScrollX: Ref<VirtualScrollXStore>): {
|
|
11
|
+
config: import('vue').ComputedRef<AreaSelectionConfig>;
|
|
11
12
|
isSelecting: Ref<boolean, boolean>;
|
|
12
13
|
getClass: (cellKey: string, absoluteRowIndex: number, colKey: UniqKey) => string[];
|
|
13
14
|
get: () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComputedRef, Ref, ShallowRef } from 'vue';
|
|
2
|
-
import { StkTableColumn } from './types';
|
|
2
|
+
import { AreaSelectionConfig, StkTableColumn } from './types';
|
|
3
3
|
import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -7,4 +7,4 @@ import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
|
7
7
|
*
|
|
8
8
|
* 在低版本浏览器中,虚拟滚动时,使用键盘滚动,等选中的行消失在视口外时,滚动会失效。
|
|
9
9
|
*/
|
|
10
|
-
export declare function useKeyboardArrowScroll<DT extends Record<string, any>>(targetElement: Ref<HTMLElement | undefined>, props: any, scrollTo: (y: number | null, x: number | null) => void, virtualScroll: Ref<VirtualScrollStore>, virtualScrollX: Ref<VirtualScrollXStore>, tableHeaders: ShallowRef<StkTableColumn<DT>[][]>, virtual_on: ComputedRef<boolean>): void;
|
|
10
|
+
export declare function useKeyboardArrowScroll<DT extends Record<string, any>>(targetElement: Ref<HTMLElement | undefined>, props: any, scrollTo: (y: number | null, x: number | null) => void, virtualScroll: Ref<VirtualScrollStore>, virtualScrollX: Ref<VirtualScrollXStore>, tableHeaders: ShallowRef<StkTableColumn<DT>[][]>, virtual_on: ComputedRef<boolean>, areaSelectionConfig: ComputedRef<AreaSelectionConfig>): void;
|
|
@@ -41,7 +41,7 @@ export type VirtualScrollXStore = {
|
|
|
41
41
|
* virtual scroll
|
|
42
42
|
* @returns
|
|
43
43
|
*/
|
|
44
|
-
export declare function useVirtualScroll
|
|
44
|
+
export declare function useVirtualScroll(props: any, tableContainerRef: Ref<HTMLElement | undefined>, trRef: Ref<HTMLTableRowElement[] | undefined>, dataSourceCopy: ShallowRef<PrivateRowDT[]>, tableHeaderLast: ShallowRef<PrivateStkTableColumn<PrivateRowDT>[]>, tableHeaders: ShallowRef<PrivateStkTableColumn<PrivateRowDT>[][]>, rowKeyGen: RowKeyGen, maxRowSpan: Map<UniqKey, number>, scrollbarOptions: Ref<Required<ScrollbarOptions>>, isExperimentalScrollY: Ref<boolean | undefined>): readonly [Ref<{
|
|
45
45
|
containerHeight: number;
|
|
46
46
|
pageSize: number;
|
|
47
47
|
startIndex: number;
|
package/lib/stk-table-vue.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* name: stk-table-vue
|
|
3
|
-
* version: v0.11.
|
|
3
|
+
* version: v0.11.6
|
|
4
4
|
* description: High performance realtime virtual table for vue3 and vue2.7
|
|
5
5
|
* author: japlus
|
|
6
6
|
* homepage: https://ja-plus.github.io/stk-table-vue/
|
|
@@ -357,6 +357,13 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
357
357
|
let autoScrollRafId = 0;
|
|
358
358
|
let lastMouseClientX = 0;
|
|
359
359
|
let lastMouseClientY = 0;
|
|
360
|
+
const config = computed(() => {
|
|
361
|
+
if (typeof props.areaSelection === "boolean") {
|
|
362
|
+
const b = props.areaSelection;
|
|
363
|
+
return { enabled: b, keyboard: b };
|
|
364
|
+
}
|
|
365
|
+
return props.areaSelection;
|
|
366
|
+
});
|
|
360
367
|
const colKeyToIndexMap = computed(() => {
|
|
361
368
|
const headers = tableHeaderLast.value;
|
|
362
369
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -533,7 +540,7 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
533
540
|
return { deltaX, deltaY };
|
|
534
541
|
}
|
|
535
542
|
function onSelectionMouseDown(e) {
|
|
536
|
-
if (!
|
|
543
|
+
if (!config.value.enabled || e.button !== 0) return;
|
|
537
544
|
const rowIndex = getClosestTrIndex(e.target);
|
|
538
545
|
const colKey = getClosestColKey(e.target);
|
|
539
546
|
const colIndex = getColIndexByKey(colKey);
|
|
@@ -663,12 +670,11 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
663
670
|
emits("area-selection-change", range, { rows, cols: selectedCols });
|
|
664
671
|
}
|
|
665
672
|
function getFormatCellFn() {
|
|
666
|
-
const cfg =
|
|
667
|
-
return
|
|
673
|
+
const cfg = config.value;
|
|
674
|
+
return typeof cfg.formatCellForClipboard === "function" ? cfg.formatCellForClipboard : null;
|
|
668
675
|
}
|
|
669
676
|
const keyboardEnabled = computed(() => {
|
|
670
|
-
|
|
671
|
-
return cfg && typeof cfg === "object" && cfg.keyboard === true;
|
|
677
|
+
return config.value.keyboard;
|
|
672
678
|
});
|
|
673
679
|
function copySelectedArea() {
|
|
674
680
|
if (!selectionRange.value) return "";
|
|
@@ -700,7 +706,7 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
700
706
|
return text;
|
|
701
707
|
}
|
|
702
708
|
function onKeydown(e) {
|
|
703
|
-
if (!
|
|
709
|
+
if (!config.value.enabled) return;
|
|
704
710
|
const key = e.key;
|
|
705
711
|
if (key === KEY_ESCAPE || key === KEY_ESC) {
|
|
706
712
|
if (selectionRange.value) {
|
|
@@ -785,10 +791,11 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
785
791
|
const footerHeight = tfoot ? tfoot.offsetHeight : 0;
|
|
786
792
|
const vs = virtualScroll.value;
|
|
787
793
|
const vsx = virtualScrollX.value;
|
|
794
|
+
const isScrollRowByRow = props.scrollRowByRow;
|
|
788
795
|
const rowHeight = vs.rowHeight;
|
|
789
796
|
const targetRowTop = rowIndex * rowHeight;
|
|
790
797
|
const targetRowBottom = targetRowTop + rowHeight;
|
|
791
|
-
const visibleTop = container.scrollTop;
|
|
798
|
+
const visibleTop = isScrollRowByRow ? vs.scrollTop : container.scrollTop;
|
|
792
799
|
const visibleBottom = visibleTop + vs.containerHeight - headerHeight - footerHeight;
|
|
793
800
|
let newScrollTop = null;
|
|
794
801
|
if (targetRowTop < visibleTop) {
|
|
@@ -840,6 +847,7 @@ function useAreaSelection(props, emits, tableContainerRef, dataSourceCopy, table
|
|
|
840
847
|
isSelecting.value = false;
|
|
841
848
|
}
|
|
842
849
|
return {
|
|
850
|
+
config,
|
|
843
851
|
isSelecting,
|
|
844
852
|
getClass: getAreaSelectionClasses,
|
|
845
853
|
get: getSelectedArea,
|
|
@@ -852,6 +860,7 @@ const ON_DEMAND_FEATURE = {
|
|
|
852
860
|
[useAreaSelection.name]: () => {
|
|
853
861
|
console.warn("useAreaSelection is not registered");
|
|
854
862
|
return {
|
|
863
|
+
config: computed(() => ({ enabled: false })),
|
|
855
864
|
isSelecting: ref(false),
|
|
856
865
|
onMD: () => {
|
|
857
866
|
},
|
|
@@ -1403,7 +1412,7 @@ var ScrollCodes = /* @__PURE__ */ ((ScrollCodes2) => {
|
|
|
1403
1412
|
return ScrollCodes2;
|
|
1404
1413
|
})(ScrollCodes || {});
|
|
1405
1414
|
const ScrollCodesValues = Object.values(ScrollCodes);
|
|
1406
|
-
function useKeyboardArrowScroll(targetElement, props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on) {
|
|
1415
|
+
function useKeyboardArrowScroll(targetElement, props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on, areaSelectionConfig) {
|
|
1407
1416
|
let isMouseOver = false;
|
|
1408
1417
|
watch(virtual_on, (val) => {
|
|
1409
1418
|
if (!val) {
|
|
@@ -1430,8 +1439,7 @@ function useKeyboardArrowScroll(targetElement, props, scrollTo, virtualScroll, v
|
|
|
1430
1439
|
}
|
|
1431
1440
|
function handleKeydown(e) {
|
|
1432
1441
|
if (!virtual_on.value) return;
|
|
1433
|
-
|
|
1434
|
-
if (areaSelection && typeof areaSelection === "object" && areaSelection.keyboard) return;
|
|
1442
|
+
if (areaSelectionConfig.value.keyboard) return;
|
|
1435
1443
|
const keyCode = e.code;
|
|
1436
1444
|
if (!ScrollCodesValues.includes(keyCode)) return;
|
|
1437
1445
|
if (!isMouseOver) return;
|
|
@@ -2249,7 +2257,7 @@ function useVirtualScroll(props, tableContainerRef, trRef, dataSourceCopy, table
|
|
|
2249
2257
|
height = 0;
|
|
2250
2258
|
}
|
|
2251
2259
|
const { clientHeight, scrollHeight } = tableContainerRef.value || {};
|
|
2252
|
-
let scrollTop = ((_a = tableContainerRef.value) == null ? void 0 : _a.scrollTop) || 0;
|
|
2260
|
+
let scrollTop = isExperimentalScrollY.value ? virtualScroll.value.scrollTop : ((_a = tableContainerRef.value) == null ? void 0 : _a.scrollTop) || 0;
|
|
2253
2261
|
const rowHeight = getRowHeightFn.value();
|
|
2254
2262
|
const containerHeight = height || clientHeight || DEFAULT_TABLE_HEIGHT;
|
|
2255
2263
|
const { headless } = props;
|
|
@@ -2306,14 +2314,7 @@ function useVirtualScroll(props, tableContainerRef, trRef, dataSourceCopy, table
|
|
|
2306
2314
|
const dataSourceCopyTemp = dataSourceCopy.value;
|
|
2307
2315
|
const dataLength = dataSourceCopyTemp.length;
|
|
2308
2316
|
const rowHeight = getRowHeightFn.value();
|
|
2309
|
-
const vsValue = {
|
|
2310
|
-
startIndex: 0,
|
|
2311
|
-
// github #34 init
|
|
2312
|
-
endIndex: dataLength,
|
|
2313
|
-
// github #34 init
|
|
2314
|
-
offsetTop: 0
|
|
2315
|
-
// github #34 init
|
|
2316
|
-
};
|
|
2317
|
+
const vsValue = {};
|
|
2317
2318
|
const scrollHeight = dataLength * rowHeight + tableHeaderHeight.value;
|
|
2318
2319
|
const { enabled: scrollbarEnable } = scrollbarOptions.value;
|
|
2319
2320
|
if (scrollbarEnable) {
|
|
@@ -2327,6 +2328,7 @@ function useVirtualScroll(props, tableContainerRef, trRef, dataSourceCopy, table
|
|
|
2327
2328
|
vsValue.scrollTop = sTop;
|
|
2328
2329
|
Object.assign(virtualScroll.value, vsValue);
|
|
2329
2330
|
if (!virtual_on.value) {
|
|
2331
|
+
Object.assign(virtualScroll.value, { startIndex: 0, endIndex: 0, offsetTop: 0 });
|
|
2330
2332
|
return;
|
|
2331
2333
|
}
|
|
2332
2334
|
const { autoRowHeight, stripe, optimizeVue2Scroll } = props;
|
|
@@ -2390,7 +2392,7 @@ function useVirtualScroll(props, tableContainerRef, trRef, dataSourceCopy, table
|
|
|
2390
2392
|
startIndex = correctedStartIndex;
|
|
2391
2393
|
endIndex = correctedEndIndex;
|
|
2392
2394
|
}
|
|
2393
|
-
if (stripe && startIndex > 0 && startIndex % 2) {
|
|
2395
|
+
if (stripe && !isExperimentalScrollY.value && startIndex > 0 && startIndex % 2) {
|
|
2394
2396
|
startIndex -= 1;
|
|
2395
2397
|
if (autoRowHeight || hasExpandCol.value) {
|
|
2396
2398
|
const height = getRowHeightFn.value(dataSourceCopyTemp[startIndex]);
|
|
@@ -2896,9 +2898,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
2896
2898
|
scrollbarOptions,
|
|
2897
2899
|
isExperimentalScrollY
|
|
2898
2900
|
);
|
|
2899
|
-
const rafUpdateVirtualScrollYForWheel = rafThrottle(
|
|
2900
|
-
updateVirtualScrollY(scrollTop);
|
|
2901
|
-
});
|
|
2901
|
+
const rafUpdateVirtualScrollYForWheel = rafThrottle(updateVirtualScrollY);
|
|
2902
2902
|
const [scrollbar, showScrollbar, onVerticalScrollbarMouseDown, onHorizontalScrollbarMouseDown, updateCustomScrollbar] = useScrollbar(
|
|
2903
2903
|
props,
|
|
2904
2904
|
tableContainerRef,
|
|
@@ -2921,27 +2921,8 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
2921
2921
|
if (props.autoResize) {
|
|
2922
2922
|
useAutoResize(tableContainerRef, initVirtualScroll, props, 200);
|
|
2923
2923
|
}
|
|
2924
|
-
useKeyboardArrowScroll(tableContainerRef, props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on);
|
|
2925
|
-
const [fixedCols, fixedColClassMap, updateFixedShadow] = useFixedCol(
|
|
2926
|
-
props,
|
|
2927
|
-
colKeyGen,
|
|
2928
|
-
getFixedColPosition,
|
|
2929
|
-
tableHeaders,
|
|
2930
|
-
tableHeadersForCalc,
|
|
2931
|
-
tableContainerRef
|
|
2932
|
-
);
|
|
2933
|
-
const [colResizeOn, isColResizing, onThResizeMouseDown] = useColResize(
|
|
2934
|
-
props,
|
|
2935
|
-
emits,
|
|
2936
|
-
tableContainerRef,
|
|
2937
|
-
tableHeaderLast,
|
|
2938
|
-
colResizeIndicatorRef,
|
|
2939
|
-
colKeyGen,
|
|
2940
|
-
fixedCols
|
|
2941
|
-
);
|
|
2942
|
-
const [toggleExpandRow, setRowExpand] = useRowExpand(emits, dataSourceCopy, rowKeyGen);
|
|
2943
|
-
const [toggleTreeNode, setTreeExpand, flatTreeData] = useTree(props, dataSourceCopy, rowKeyGen, emits);
|
|
2944
2924
|
const {
|
|
2925
|
+
config: areaSelectionConfig,
|
|
2945
2926
|
isSelecting: isAreaSelecting,
|
|
2946
2927
|
onMD: onSelectionMouseDown,
|
|
2947
2928
|
getClass: getAreaSelectionClasses,
|
|
@@ -2960,6 +2941,26 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
2960
2941
|
virtualScroll,
|
|
2961
2942
|
virtualScrollX
|
|
2962
2943
|
);
|
|
2944
|
+
useKeyboardArrowScroll(tableContainerRef, props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on, areaSelectionConfig);
|
|
2945
|
+
const [fixedCols, fixedColClassMap, updateFixedShadow] = useFixedCol(
|
|
2946
|
+
props,
|
|
2947
|
+
colKeyGen,
|
|
2948
|
+
getFixedColPosition,
|
|
2949
|
+
tableHeaders,
|
|
2950
|
+
tableHeadersForCalc,
|
|
2951
|
+
tableContainerRef
|
|
2952
|
+
);
|
|
2953
|
+
const [colResizeOn, isColResizing, onThResizeMouseDown] = useColResize(
|
|
2954
|
+
props,
|
|
2955
|
+
emits,
|
|
2956
|
+
tableContainerRef,
|
|
2957
|
+
tableHeaderLast,
|
|
2958
|
+
colResizeIndicatorRef,
|
|
2959
|
+
colKeyGen,
|
|
2960
|
+
fixedCols
|
|
2961
|
+
);
|
|
2962
|
+
const [toggleExpandRow, setRowExpand] = useRowExpand(emits, dataSourceCopy, rowKeyGen);
|
|
2963
|
+
const [toggleTreeNode, setTreeExpand, flatTreeData] = useTree(props, dataSourceCopy, rowKeyGen, emits);
|
|
2963
2964
|
watch(
|
|
2964
2965
|
() => props.columns,
|
|
2965
2966
|
() => {
|
|
@@ -3205,7 +3206,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
3205
3206
|
if (props.cellActive && currentSelectedCellKey.value === cellKey) {
|
|
3206
3207
|
classList.push("active");
|
|
3207
3208
|
}
|
|
3208
|
-
if (
|
|
3209
|
+
if (areaSelectionConfig.value.enabled) {
|
|
3209
3210
|
const absRowIndex = getRowIndex(rowIndex);
|
|
3210
3211
|
classList.push(...getAreaSelectionClasses(cellKey, absRowIndex, colKey));
|
|
3211
3212
|
}
|
|
@@ -3311,7 +3312,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
3311
3312
|
function onCellMouseDown(e) {
|
|
3312
3313
|
const { row, col, rowIndex } = getCellEventData(e);
|
|
3313
3314
|
emits("cell-mousedown", e, row, col, { rowIndex });
|
|
3314
|
-
if (
|
|
3315
|
+
if (areaSelectionConfig.value.enabled) {
|
|
3315
3316
|
onSelectionMouseDown(e);
|
|
3316
3317
|
}
|
|
3317
3318
|
}
|
|
@@ -3474,7 +3475,14 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
3474
3475
|
}
|
|
3475
3476
|
function scrollTo(top = 0, left = 0) {
|
|
3476
3477
|
if (!tableContainerRef.value) return;
|
|
3477
|
-
if (top !== null)
|
|
3478
|
+
if (top !== null) {
|
|
3479
|
+
if (isExperimentalScrollY.value) {
|
|
3480
|
+
updateVirtualScrollY(top);
|
|
3481
|
+
updateCustomScrollbar();
|
|
3482
|
+
} else {
|
|
3483
|
+
tableContainerRef.value.scrollTop = top;
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3478
3486
|
if (left !== null) tableContainerRef.value.scrollLeft = left;
|
|
3479
3487
|
}
|
|
3480
3488
|
function getTableData() {
|
|
@@ -3663,7 +3671,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
3663
3671
|
"is-area-selecting": unref(isAreaSelecting),
|
|
3664
3672
|
"exp-scroll-y": isExperimentalScrollY.value
|
|
3665
3673
|
}]),
|
|
3666
|
-
tabindex:
|
|
3674
|
+
tabindex: unref(areaSelectionConfig).enabled ? 0 : void 0,
|
|
3667
3675
|
style: normalizeStyle({
|
|
3668
3676
|
"--row-height": props.autoRowHeight ? void 0 : unref(virtualScroll).rowHeight + "px",
|
|
3669
3677
|
"--header-row-height": props.headerRowHeight + "px",
|
package/lib/style.css
CHANGED
package/package.json
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
'is-area-selecting': isAreaSelecting,
|
|
29
29
|
'exp-scroll-y': isExperimentalScrollY,
|
|
30
30
|
}"
|
|
31
|
-
:tabindex="
|
|
31
|
+
:tabindex="areaSelectionConfig.enabled ? 0 : void 0"
|
|
32
32
|
:style="{
|
|
33
33
|
'--row-height': props.autoRowHeight ? void 0 : virtualScroll.rowHeight + 'px',
|
|
34
34
|
'--header-row-height': props.headerRowHeight + 'px',
|
|
@@ -864,9 +864,7 @@ const [
|
|
|
864
864
|
);
|
|
865
865
|
|
|
866
866
|
/** requestAnimationFrame throttled version of updateVirtualScrollY for smoother wheel scrolling */
|
|
867
|
-
const rafUpdateVirtualScrollYForWheel = rafThrottle(
|
|
868
|
-
updateVirtualScrollY(scrollTop);
|
|
869
|
-
});
|
|
867
|
+
const rafUpdateVirtualScrollYForWheel = rafThrottle(updateVirtualScrollY);
|
|
870
868
|
|
|
871
869
|
const [scrollbar, showScrollbar, onVerticalScrollbarMouseDown, onHorizontalScrollbarMouseDown, updateCustomScrollbar] = useScrollbar(
|
|
872
870
|
props,
|
|
@@ -896,8 +894,29 @@ if (props.autoResize) {
|
|
|
896
894
|
useAutoResize(tableContainerRef, initVirtualScroll, props, 200);
|
|
897
895
|
}
|
|
898
896
|
|
|
897
|
+
const {
|
|
898
|
+
config: areaSelectionConfig,
|
|
899
|
+
isSelecting: isAreaSelecting,
|
|
900
|
+
onMD: onSelectionMouseDown,
|
|
901
|
+
getClass: getAreaSelectionClasses,
|
|
902
|
+
get: getSelectedArea,
|
|
903
|
+
clear: clearSelectedArea,
|
|
904
|
+
copy: copySelectedArea,
|
|
905
|
+
} = ON_DEMAND_FEATURE[useAreaSelection.name](
|
|
906
|
+
props,
|
|
907
|
+
emits,
|
|
908
|
+
tableContainerRef,
|
|
909
|
+
dataSourceCopy,
|
|
910
|
+
tableHeaderLast,
|
|
911
|
+
colKeyGen,
|
|
912
|
+
cellKeyGen,
|
|
913
|
+
scrollTo,
|
|
914
|
+
virtualScroll,
|
|
915
|
+
virtualScrollX,
|
|
916
|
+
);
|
|
917
|
+
|
|
899
918
|
/** 键盘箭头滚动 */
|
|
900
|
-
useKeyboardArrowScroll(tableContainerRef, props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on);
|
|
919
|
+
useKeyboardArrowScroll(tableContainerRef, props, scrollTo, virtualScroll, virtualScrollX, tableHeaders, virtual_on, areaSelectionConfig);
|
|
901
920
|
|
|
902
921
|
/** 固定列处理 */
|
|
903
922
|
const [fixedCols, fixedColClassMap, updateFixedShadow] = useFixedCol(
|
|
@@ -923,26 +942,6 @@ const [toggleExpandRow, setRowExpand] = useRowExpand(emits, dataSourceCopy, rowK
|
|
|
923
942
|
|
|
924
943
|
const [toggleTreeNode, setTreeExpand, flatTreeData] = useTree(props, dataSourceCopy, rowKeyGen, emits);
|
|
925
944
|
|
|
926
|
-
const {
|
|
927
|
-
isSelecting: isAreaSelecting,
|
|
928
|
-
onMD: onSelectionMouseDown,
|
|
929
|
-
getClass: getAreaSelectionClasses,
|
|
930
|
-
get: getSelectedArea,
|
|
931
|
-
clear: clearSelectedArea,
|
|
932
|
-
copy: copySelectedArea,
|
|
933
|
-
} = ON_DEMAND_FEATURE[useAreaSelection.name](
|
|
934
|
-
props,
|
|
935
|
-
emits,
|
|
936
|
-
tableContainerRef,
|
|
937
|
-
dataSourceCopy,
|
|
938
|
-
tableHeaderLast,
|
|
939
|
-
colKeyGen,
|
|
940
|
-
cellKeyGen,
|
|
941
|
-
scrollTo,
|
|
942
|
-
virtualScroll,
|
|
943
|
-
virtualScrollX,
|
|
944
|
-
);
|
|
945
|
-
|
|
946
945
|
watch(
|
|
947
946
|
() => props.columns,
|
|
948
947
|
() => {
|
|
@@ -1240,7 +1239,7 @@ function getTDProps(row: PrivateRowDT | null | undefined, col: StkTableColumn<Pr
|
|
|
1240
1239
|
}
|
|
1241
1240
|
|
|
1242
1241
|
// 单元格拖选选区样式
|
|
1243
|
-
if (
|
|
1242
|
+
if (areaSelectionConfig.value.enabled) {
|
|
1244
1243
|
const absRowIndex = getRowIndex(rowIndex);
|
|
1245
1244
|
classList.push(...getAreaSelectionClasses(cellKey, absRowIndex, colKey));
|
|
1246
1245
|
}
|
|
@@ -1363,7 +1362,7 @@ function onCellMouseDown(e: MouseEvent) {
|
|
|
1363
1362
|
const { row, col, rowIndex } = getCellEventData(e);
|
|
1364
1363
|
emits('cell-mousedown', e, row, col, { rowIndex });
|
|
1365
1364
|
// 单元格拖选
|
|
1366
|
-
if (
|
|
1365
|
+
if (areaSelectionConfig.value.enabled) {
|
|
1367
1366
|
onSelectionMouseDown(e);
|
|
1368
1367
|
}
|
|
1369
1368
|
}
|
|
@@ -1570,7 +1569,14 @@ function setSelectedCell(row?: DT, col?: StkTableColumn<DT>, option = { silent:
|
|
|
1570
1569
|
*/
|
|
1571
1570
|
function scrollTo(top: number | null = 0, left: number | null = 0) {
|
|
1572
1571
|
if (!tableContainerRef.value) return;
|
|
1573
|
-
if (top !== null)
|
|
1572
|
+
if (top !== null) {
|
|
1573
|
+
if (isExperimentalScrollY.value) {
|
|
1574
|
+
updateVirtualScrollY(top);
|
|
1575
|
+
updateCustomScrollbar();
|
|
1576
|
+
} else {
|
|
1577
|
+
tableContainerRef.value.scrollTop = top;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1574
1580
|
if (left !== null) tableContainerRef.value.scrollLeft = left;
|
|
1575
1581
|
}
|
|
1576
1582
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Ref, ShallowRef, computed, onBeforeUnmount, onMounted, ref } from 'vue';
|
|
2
|
-
import { AreaSelectionRange, CellKeyGen, ColKeyGen, StkTableColumn, UniqKey } from '../types';
|
|
2
|
+
import { AreaSelectionConfig, AreaSelectionRange, CellKeyGen, ColKeyGen, StkTableColumn, UniqKey } from '../types';
|
|
3
3
|
import { VirtualScrollStore, VirtualScrollXStore } from '../useVirtualScroll';
|
|
4
4
|
import { getClosestColKey, getClosestTrIndex } from '../utils';
|
|
5
5
|
import { getCalculatedColWidth } from '../utils/constRefUtils';
|
|
@@ -62,6 +62,14 @@ export function useAreaSelection<DT extends Record<string, any>>(
|
|
|
62
62
|
let lastMouseClientX = 0;
|
|
63
63
|
let lastMouseClientY = 0;
|
|
64
64
|
|
|
65
|
+
const config = computed<AreaSelectionConfig>(() => {
|
|
66
|
+
if (typeof props.areaSelection === 'boolean') {
|
|
67
|
+
const b = props.areaSelection;
|
|
68
|
+
return { enabled: b, keyboard: b };
|
|
69
|
+
}
|
|
70
|
+
return props.areaSelection;
|
|
71
|
+
});
|
|
72
|
+
|
|
65
73
|
/** colKey → absolute index 映射 */
|
|
66
74
|
const colKeyToIndexMap = computed(() => {
|
|
67
75
|
const headers = tableHeaderLast.value;
|
|
@@ -292,7 +300,7 @@ export function useAreaSelection<DT extends Record<string, any>>(
|
|
|
292
300
|
|
|
293
301
|
/** mousedown 处理:设置锚点,开始拖选 */
|
|
294
302
|
function onSelectionMouseDown(e: MouseEvent) {
|
|
295
|
-
if (!
|
|
303
|
+
if (!config.value.enabled || e.button !== 0) return;
|
|
296
304
|
|
|
297
305
|
const rowIndex = getClosestTrIndex(e.target as HTMLElement);
|
|
298
306
|
const colKey = getClosestColKey(e.target as HTMLElement);
|
|
@@ -483,14 +491,13 @@ export function useAreaSelection<DT extends Record<string, any>>(
|
|
|
483
491
|
|
|
484
492
|
/** 获取 areaSelection 配置中的格式化回调 */
|
|
485
493
|
function getFormatCellFn() {
|
|
486
|
-
const cfg =
|
|
487
|
-
return
|
|
494
|
+
const cfg = config.value;
|
|
495
|
+
return typeof cfg.formatCellForClipboard === 'function' ? cfg.formatCellForClipboard : null;
|
|
488
496
|
}
|
|
489
497
|
|
|
490
498
|
/** 是否启用键盘控制选区移动 */
|
|
491
499
|
const keyboardEnabled = computed(() => {
|
|
492
|
-
|
|
493
|
-
return cfg && typeof cfg === 'object' && cfg.keyboard === true;
|
|
500
|
+
return config.value.keyboard;
|
|
494
501
|
});
|
|
495
502
|
|
|
496
503
|
/**
|
|
@@ -538,7 +545,7 @@ export function useAreaSelection<DT extends Record<string, any>>(
|
|
|
538
545
|
* Arrow keys / Tab 移动选区(keyboard=true时)
|
|
539
546
|
**/
|
|
540
547
|
function onKeydown(e: KeyboardEvent) {
|
|
541
|
-
if (!
|
|
548
|
+
if (!config.value.enabled) return;
|
|
542
549
|
|
|
543
550
|
const key = e.key;
|
|
544
551
|
|
|
@@ -666,13 +673,17 @@ export function useAreaSelection<DT extends Record<string, any>>(
|
|
|
666
673
|
const vs = virtualScroll.value;
|
|
667
674
|
const vsx = virtualScrollX.value;
|
|
668
675
|
|
|
676
|
+
// 是否开启按行滚动模式(experimental.scrollY 模式)
|
|
677
|
+
const isScrollRowByRow = props.scrollRowByRow;
|
|
678
|
+
|
|
669
679
|
// 计算目标行的位置(基于虚拟滚动数据)
|
|
670
680
|
const rowHeight = vs.rowHeight;
|
|
671
681
|
const targetRowTop = rowIndex * rowHeight;
|
|
672
682
|
const targetRowBottom = targetRowTop + rowHeight;
|
|
673
683
|
|
|
674
684
|
// 计算可视区域
|
|
675
|
-
|
|
685
|
+
// experimental.scrollY 模式下,容器 scrollTop 始终为 0,需要使用 virtualScroll.scrollTop
|
|
686
|
+
const visibleTop = isScrollRowByRow ? vs.scrollTop : container.scrollTop;
|
|
676
687
|
const visibleBottom = visibleTop + vs.containerHeight - headerHeight - footerHeight;
|
|
677
688
|
|
|
678
689
|
// 计算需要的垂直滚动位置
|
|
@@ -681,7 +692,7 @@ export function useAreaSelection<DT extends Record<string, any>>(
|
|
|
681
692
|
// 目标行在可视区域上方,滚动到使目标行位于顶部
|
|
682
693
|
newScrollTop = targetRowTop;
|
|
683
694
|
} else if (targetRowBottom > visibleBottom) {
|
|
684
|
-
//
|
|
695
|
+
// 目标行在可视区域下方
|
|
685
696
|
newScrollTop = targetRowBottom - (vs.containerHeight - headerHeight - footerHeight);
|
|
686
697
|
}
|
|
687
698
|
|
|
@@ -704,7 +715,6 @@ export function useAreaSelection<DT extends Record<string, any>>(
|
|
|
704
715
|
newScrollLeft = targetColRight - vsx.containerWidth + rightFixedWidth;
|
|
705
716
|
}
|
|
706
717
|
|
|
707
|
-
// 执行滚动
|
|
708
718
|
if (newScrollTop !== null || newScrollLeft !== null) {
|
|
709
719
|
scrollTo(newScrollTop, newScrollLeft);
|
|
710
720
|
}
|
|
@@ -755,6 +765,7 @@ export function useAreaSelection<DT extends Record<string, any>>(
|
|
|
755
765
|
}
|
|
756
766
|
|
|
757
767
|
return {
|
|
768
|
+
config,
|
|
758
769
|
isSelecting,
|
|
759
770
|
getClass: getAreaSelectionClasses,
|
|
760
771
|
get: getSelectedArea,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref } from 'vue';
|
|
1
|
+
import { computed, ref } from 'vue';
|
|
2
2
|
import { useAreaSelection } from './features';
|
|
3
3
|
|
|
4
4
|
type OnDemandFeature = {
|
|
@@ -9,6 +9,7 @@ export const ON_DEMAND_FEATURE: OnDemandFeature = {
|
|
|
9
9
|
[useAreaSelection.name]: (() => {
|
|
10
10
|
console.warn('useAreaSelection is not registered');
|
|
11
11
|
return {
|
|
12
|
+
config: computed(() => ({ enabled: false })),
|
|
12
13
|
isSelecting: ref(false),
|
|
13
14
|
onMD: () => {},
|
|
14
15
|
getClass: () => [],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComputedRef, Ref, ShallowRef, onBeforeUnmount, onMounted, watch } from 'vue';
|
|
2
|
-
import { StkTableColumn } from './types';
|
|
2
|
+
import { AreaSelectionConfig, StkTableColumn } from './types';
|
|
3
3
|
import { VirtualScrollStore, VirtualScrollXStore } from './useVirtualScroll';
|
|
4
4
|
|
|
5
5
|
/** 翻页按键 */
|
|
@@ -29,6 +29,7 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
|
|
|
29
29
|
virtualScrollX: Ref<VirtualScrollXStore>,
|
|
30
30
|
tableHeaders: ShallowRef<StkTableColumn<DT>[][]>,
|
|
31
31
|
virtual_on: ComputedRef<boolean>,
|
|
32
|
+
areaSelectionConfig: ComputedRef<AreaSelectionConfig>,
|
|
32
33
|
) {
|
|
33
34
|
/** 检测鼠标是否悬浮在表格体上 */
|
|
34
35
|
let isMouseOver = false;
|
|
@@ -62,8 +63,7 @@ export function useKeyboardArrowScroll<DT extends Record<string, any>>(
|
|
|
62
63
|
function handleKeydown(e: KeyboardEvent) {
|
|
63
64
|
if (!virtual_on.value) return; // 非虚拟滚动使用浏览器默认滚动
|
|
64
65
|
// 如果单元格选区键盘控制已启用,则不处理滚动,交给 useAreaSelection 处理
|
|
65
|
-
|
|
66
|
-
if (areaSelection && typeof areaSelection === 'object' && areaSelection.keyboard) return;
|
|
66
|
+
if (areaSelectionConfig.value.keyboard) return;
|
|
67
67
|
const keyCode = e.code;
|
|
68
68
|
if (!ScrollCodesValues.includes(keyCode as any)) return;
|
|
69
69
|
if (!isMouseOver) return; // 不悬浮还是要触发键盘事件的
|
|
@@ -47,7 +47,7 @@ const VUE2_SCROLL_TIMEOUT_MS = 200;
|
|
|
47
47
|
* virtual scroll
|
|
48
48
|
* @returns
|
|
49
49
|
*/
|
|
50
|
-
export function useVirtualScroll
|
|
50
|
+
export function useVirtualScroll(
|
|
51
51
|
props: any,
|
|
52
52
|
tableContainerRef: Ref<HTMLElement | undefined>,
|
|
53
53
|
trRef: Ref<HTMLTableRowElement[] | undefined>,
|
|
@@ -201,7 +201,9 @@ export function useVirtualScroll<DT extends Record<string, any>>(
|
|
|
201
201
|
height = 0;
|
|
202
202
|
}
|
|
203
203
|
const { clientHeight, scrollHeight } = tableContainerRef.value || {};
|
|
204
|
-
|
|
204
|
+
// 当 isExperimentalScrollY 为 true 时,DOM 的 scrollTop 始终为 0(纵向滚动通过 transform 模拟)
|
|
205
|
+
// 此时应该使用 virtualScroll 中保存的 scrollTop 值
|
|
206
|
+
let scrollTop = isExperimentalScrollY.value ? virtualScroll.value.scrollTop : tableContainerRef.value?.scrollTop || 0;
|
|
205
207
|
|
|
206
208
|
const rowHeight = getRowHeightFn.value();
|
|
207
209
|
const containerHeight = height || clientHeight || DEFAULT_TABLE_HEIGHT;
|
|
@@ -272,11 +274,7 @@ export function useVirtualScroll<DT extends Record<string, any>>(
|
|
|
272
274
|
const dataLength = dataSourceCopyTemp.length;
|
|
273
275
|
const rowHeight = getRowHeightFn.value();
|
|
274
276
|
|
|
275
|
-
const vsValue: any = {
|
|
276
|
-
startIndex: 0, // github #34 init
|
|
277
|
-
endIndex: dataLength, // github #34 init
|
|
278
|
-
offsetTop: 0, // github #34 init
|
|
279
|
-
};
|
|
277
|
+
const vsValue: any = {};
|
|
280
278
|
const scrollHeight = dataLength * rowHeight + tableHeaderHeight.value;
|
|
281
279
|
const { enabled: scrollbarEnable } = scrollbarOptions.value;
|
|
282
280
|
if (scrollbarEnable) {
|
|
@@ -292,6 +290,8 @@ export function useVirtualScroll<DT extends Record<string, any>>(
|
|
|
292
290
|
Object.assign(virtualScroll.value, vsValue);
|
|
293
291
|
|
|
294
292
|
if (!virtual_on.value) {
|
|
293
|
+
// github #34 init
|
|
294
|
+
Object.assign(virtualScroll.value, { startIndex: 0, endIndex: 0, offsetTop: 0 });
|
|
295
295
|
return;
|
|
296
296
|
}
|
|
297
297
|
|
|
@@ -372,7 +372,7 @@ export function useVirtualScroll<DT extends Record<string, any>>(
|
|
|
372
372
|
endIndex = correctedEndIndex;
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
-
if (stripe && startIndex > 0 && startIndex % 2) {
|
|
375
|
+
if (stripe && !isExperimentalScrollY.value && startIndex > 0 && startIndex % 2) {
|
|
376
376
|
// 斑马纹情况下,每滚动偶数行才加载。防止斑马纹错位。
|
|
377
377
|
startIndex -= 1; // 奇数-1变成偶数
|
|
378
378
|
if (autoRowHeight || hasExpandCol.value) {
|