zmdms-webui 2.4.1 → 2.4.3
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.
|
@@ -39,7 +39,8 @@ import { getTableColumns } from '../table/utils.js';
|
|
|
39
39
|
import DynamicSetting from '../dynamicsetting/dynamicSetting.js';
|
|
40
40
|
|
|
41
41
|
function CanvasTable(props) {
|
|
42
|
-
var _a = props.dataSource, dataSource = _a === void 0 ? [] : _a, _b = props.columns, columns = _b === void 0 ? [] : _b, _c = props.rowKey, rowKey = _c === void 0 ? "id" : _c, _d = props.height, height = _d === void 0 ? 600 : _d, width = props.width, _e = props.rowHeight, rowHeight = _e === void 0 ? 36 : _e, _f = props.headerHeight, headerHeight = _f === void 0 ? 36 : _f, rowSelection = props.rowSelection, onSortChange = props.onSortChange, onFilterChange = props.onFilterChange, onScroll = props.onScroll, onRowClick = props.onRowClick, onColumnResize = props.onColumnResize, _g = props.bordered, bordered = _g === void 0 ? true : _g, _h = props.striped, striped = _h === void 0 ? false : _h, _j = props.emptyText, emptyText = _j === void 0 ? "暂无数据" : _j, style = props.style, className = props.className, _k = props.loading, loading = _k === void 0 ? false : _k, _l = props.isContextMenu, isContextMenu = _l === void 0 ? true : _l, isFullscreenHandle = props.isFullscreenHandle,
|
|
42
|
+
var _a = props.dataSource, dataSource = _a === void 0 ? [] : _a, _b = props.columns, columns = _b === void 0 ? [] : _b, _c = props.rowKey, rowKey = _c === void 0 ? "id" : _c, _d = props.height, height = _d === void 0 ? 600 : _d, width = props.width, _e = props.rowHeight, rowHeight = _e === void 0 ? 36 : _e, _f = props.headerHeight, headerHeight = _f === void 0 ? 36 : _f, rowSelection = props.rowSelection, onSortChange = props.onSortChange, onFilterChange = props.onFilterChange, onScroll = props.onScroll, onRowClick = props.onRowClick, onColumnResize = props.onColumnResize, _g = props.bordered, bordered = _g === void 0 ? true : _g, _h = props.striped, striped = _h === void 0 ? false : _h, _j = props.emptyText, emptyText = _j === void 0 ? "暂无数据" : _j, style = props.style, className = props.className, _k = props.loading, loading = _k === void 0 ? false : _k, _l = props.isContextMenu, isContextMenu = _l === void 0 ? true : _l, isFullscreenHandle = props.isFullscreenHandle, mode = props.mode, dynamicKey = props.dynamicKey, dynamicVersion = props.dynamicVersion, customDynamicListHandle = props.customDynamicListHandle, isDimensionDynamic = props.isDimensionDynamic, dimensionCustomSumKeys = props.dimensionCustomSumKeys, isAutoMerge = props.isAutoMerge, _m = props.isIndexMerge, isIndexMerge = _m === void 0 ? true : _m, _o = props.isSelectionMerge, isSelectionMerge = _o === void 0 ? false : _o, _p = props.renderMode, renderMode = _p === void 0 ? "object" : _p, fixedRowsCount = props.fixedRowsCount, fixedRowsConfig = props.fixedRowsConfig, _q = props.summaryFixed, summaryFixed = _q === void 0 ? false : _q, _r = props.isAutoScrollY, isAutoScrollY = _r === void 0 ? false : _r, _s = props.autoScrollYMarginBottom, autoScrollYMarginBottom = _s === void 0 ? 65 : _s, canvasTableId = props.canvasTableId, headerWrap = props.headerWrap, _t = props.headerAlign, headerAlign = _t === void 0 ? "center" : _t, tableRefHandle = props.tableRefHandle, exportExcelConfig = props.exportExcelConfig;
|
|
43
|
+
var actualMode = "mode" in props ? mode : "index";
|
|
43
44
|
var canvasRef = useRef(null);
|
|
44
45
|
var containerRef = useRef(null);
|
|
45
46
|
var filterPopoverRef = useRef(null);
|
|
@@ -61,22 +62,22 @@ function CanvasTable(props) {
|
|
|
61
62
|
return String((_a = record[rowKey]) !== null && _a !== void 0 ? _a : index);
|
|
62
63
|
}, [rowKey]);
|
|
63
64
|
// 动态列配置
|
|
64
|
-
var
|
|
65
|
+
var _u = useDynamicListByColumns(columns, {
|
|
65
66
|
dynamicKey: dynamicKey,
|
|
66
67
|
dynamicVersion: dynamicVersion,
|
|
67
68
|
customDynamicListHandle: customDynamicListHandle,
|
|
68
|
-
}), defaultDynamicList =
|
|
69
|
+
}), defaultDynamicList = _u.defaultDynamicList, currentDynamicList = _u.currentDynamicList, onCurrentListChange = _u.onCurrentListChange, dynamicSettingRef = _u.dynamicSettingRef;
|
|
69
70
|
// 根据动态列配置处理columns
|
|
70
71
|
var dynamicColumns = useMemo(function () { return getTableColumns(columns, currentDynamicList); }, [columns, currentDynamicList]).columns;
|
|
71
72
|
// 内部列宽状态(未开启动态配置时使用)
|
|
72
|
-
var
|
|
73
|
+
var _v = useState({}), internalColumnWidths = _v[0], setInternalColumnWidths = _v[1];
|
|
73
74
|
// 跟踪用户手动调整过宽度的列(用于排除自动宽度分配)
|
|
74
|
-
var
|
|
75
|
+
var _w = useState(new Set()), manuallyResizedColumnKeys = _w[0], setManuallyResizedColumnKeys = _w[1];
|
|
75
76
|
// 处理选中框列、序号列等
|
|
76
77
|
var processedColumnsOld = useProcessedColumns({
|
|
77
78
|
columns: columns,
|
|
78
79
|
dynamicColumns: dynamicColumns,
|
|
79
|
-
mode:
|
|
80
|
+
mode: actualMode,
|
|
80
81
|
rowSelection: rowSelection,
|
|
81
82
|
internalColumnWidths: internalColumnWidths,
|
|
82
83
|
dynamicKey: dynamicKey,
|
|
@@ -86,29 +87,29 @@ function CanvasTable(props) {
|
|
|
86
87
|
headerAlign: headerAlign,
|
|
87
88
|
});
|
|
88
89
|
// 表格状态管理
|
|
89
|
-
var
|
|
90
|
+
var _x = useTableState({
|
|
90
91
|
dataSource: dataSource,
|
|
91
92
|
columns: processedColumnsOld,
|
|
92
93
|
rowSelection: rowSelection,
|
|
93
94
|
onFilterChange: onFilterChange,
|
|
94
95
|
isAutoMerge: isAutoMerge,
|
|
95
|
-
}), state =
|
|
96
|
+
}), state = _x.state, setState = _x.setState, processedDataSource = _x.processedDataSource, handleFilterChange = _x.handleFilterChange, closeFilterPopover = _x.closeFilterPopover, autoGeneratedFilters = _x.autoGeneratedFilters;
|
|
96
97
|
var order = useMemo(function () {
|
|
97
98
|
return state.sortOrder && state.sortField
|
|
98
99
|
? { field: state.sortField, order: state.sortOrder }
|
|
99
100
|
: undefined;
|
|
100
101
|
}, [state.sortOrder, state.sortField]);
|
|
101
|
-
var
|
|
102
|
+
var _y = useAutoMerge(processedDataSource, processedColumnsOld, {
|
|
102
103
|
isAutoMerge: isAutoMerge,
|
|
103
104
|
isDimensionDynamic: isDimensionDynamic,
|
|
104
105
|
order: order,
|
|
105
106
|
dimensionCustomSumKeys: dimensionCustomSumKeys,
|
|
106
|
-
}), newDataSource =
|
|
107
|
+
}), newDataSource = _y[0], processedColumns = _y[1];
|
|
107
108
|
// 生成合计行和最终数据源
|
|
108
|
-
var
|
|
109
|
+
var _z = useSummaryRow({
|
|
109
110
|
columns: processedColumns,
|
|
110
111
|
dataSource: newDataSource,
|
|
111
|
-
}), finalDataSource =
|
|
112
|
+
}), finalDataSource = _z.finalDataSource, hasSummaryRow = _z.hasSummaryRow;
|
|
112
113
|
// 自动高度计算(需要在容器尺寸计算之前)
|
|
113
114
|
var autoHeight = useCanvasTableAutoHeight(isAutoScrollY, autoScrollYMarginBottom, canvasTableId);
|
|
114
115
|
// 监听容器尺寸变化(提前计算,用于列宽自适应)
|
|
@@ -144,7 +145,7 @@ function CanvasTable(props) {
|
|
|
144
145
|
return calculateTotalHeight(calculatedHeaderHeight, finalDataSource.length, rowHeight);
|
|
145
146
|
}, [calculatedHeaderHeight, finalDataSource.length, rowHeight]);
|
|
146
147
|
// 计算滚动条指标
|
|
147
|
-
var
|
|
148
|
+
var _0 = useScrollbarMetrics({
|
|
148
149
|
containerWidth: containerWidth,
|
|
149
150
|
containerHeight: containerHeight,
|
|
150
151
|
totalWidth: totalWidth,
|
|
@@ -152,14 +153,14 @@ function CanvasTable(props) {
|
|
|
152
153
|
headerHeight: calculatedHeaderHeight,
|
|
153
154
|
scrollTop: 0,
|
|
154
155
|
scrollLeft: 0,
|
|
155
|
-
}), maxScrollTop =
|
|
156
|
+
}), maxScrollTop = _0.maxScrollTop, maxScrollLeft = _0.maxScrollLeft;
|
|
156
157
|
// 滚动管理(使用预先计算的maxScrollTop和maxScrollLeft)
|
|
157
|
-
var
|
|
158
|
+
var _1 = useTableScroll({
|
|
158
159
|
containerRef: containerRef,
|
|
159
160
|
maxScrollTop: maxScrollTop,
|
|
160
161
|
maxScrollLeft: maxScrollLeft,
|
|
161
162
|
onScroll: onScroll,
|
|
162
|
-
}), scrollState =
|
|
163
|
+
}), scrollState = _1.scrollState, setScrollState = _1.setScrollState;
|
|
163
164
|
// 数据变化时重置滚动位置(筛选、排序、数据源更新等操作后)
|
|
164
165
|
useScrollReset({
|
|
165
166
|
dataSourceLength: dataSource.length,
|
|
@@ -180,12 +181,12 @@ function CanvasTable(props) {
|
|
|
180
181
|
scrollLeft: scrollState.scrollLeft,
|
|
181
182
|
}).actualMetrics;
|
|
182
183
|
// 单元格框选
|
|
183
|
-
var
|
|
184
|
+
var _2 = useTableSelection({
|
|
184
185
|
state: state,
|
|
185
186
|
setState: setState,
|
|
186
187
|
}),
|
|
187
188
|
// selectionStartRef,
|
|
188
|
-
startSelection =
|
|
189
|
+
startSelection = _2.startSelection, updateSelection = _2.updateSelection, extendSelection = _2.extendSelection;
|
|
189
190
|
// 处理列宽调整
|
|
190
191
|
var handleColumnResize = useCallback(function (columnKey, newWidth) {
|
|
191
192
|
var _a;
|
|
@@ -240,13 +241,13 @@ function CanvasTable(props) {
|
|
|
240
241
|
onCurrentListChange,
|
|
241
242
|
]);
|
|
242
243
|
// 列宽调整
|
|
243
|
-
var
|
|
244
|
+
var _3 = useColumnResize({
|
|
244
245
|
columnRenderInfos: columnRenderInfos,
|
|
245
246
|
containerWidth: containerWidth,
|
|
246
247
|
headerHeight: calculatedHeaderHeight,
|
|
247
248
|
scrollLeft: scrollState.scrollLeft,
|
|
248
249
|
onColumnResize: handleColumnResize,
|
|
249
|
-
}), resizeState =
|
|
250
|
+
}), resizeState = _3.resizeState, checkResizeHandle = _3.checkResizeHandle, startResize = _3.startResize, updateResize = _3.updateResize, endResize = _3.endResize, setHoverResizeColumn = _3.setHoverResizeColumn, getColumnWidth = _3.getColumnWidth, RESIZE_HANDLE_WIDTH = _3.RESIZE_HANDLE_WIDTH;
|
|
250
251
|
// 复制到剪贴板
|
|
251
252
|
var getSelectedCellsText = useCopyToClipboard({
|
|
252
253
|
cellSelection: state.cellSelection,
|
|
@@ -274,7 +275,7 @@ function CanvasTable(props) {
|
|
|
274
275
|
summaryConfig: [],
|
|
275
276
|
});
|
|
276
277
|
// 交互事件处理(使用baseScrollbarMetrics的maxScrollTop/maxScrollLeft以保持稳定)
|
|
277
|
-
var
|
|
278
|
+
var _4 = useTableInteraction({
|
|
278
279
|
state: state,
|
|
279
280
|
setState: setState,
|
|
280
281
|
scrollState: scrollState,
|
|
@@ -321,7 +322,7 @@ function CanvasTable(props) {
|
|
|
321
322
|
fixedRowsCount: fixedRowsCount,
|
|
322
323
|
fixedRowsConfig: fixedRowsConfig,
|
|
323
324
|
summaryFixed: summaryFixed,
|
|
324
|
-
}), handleCanvasMouseDown =
|
|
325
|
+
}), handleCanvasMouseDown = _4.handleCanvasMouseDown, handleCanvasMouseMove = _4.handleCanvasMouseMove, handleCanvasMouseUp = _4.handleCanvasMouseUp, handleCanvasMouseLeave = _4.handleCanvasMouseLeave, handleCanvasContextMenu = _4.handleCanvasContextMenu;
|
|
325
326
|
// 渲染表格
|
|
326
327
|
useTableRender(__assign(__assign({ canvasRef: canvasRef, processedDataSource: finalDataSource, columnRenderInfos: columnRenderInfos, columns: processedColumns, // 传递原始columns用于渲染多级表头
|
|
327
328
|
state: state, scrollState: scrollState, rowSelection: rowSelection, containerWidth: containerWidth, containerHeight: containerHeight, headerHeight: calculatedHeaderHeight, baseHeaderHeight: headerHeight, // 传入原始基础高度用于计算每层高度
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __assign } from '../../_virtual/_tslib.js';
|
|
2
|
-
import { useMemo, useState, useRef, useEffect } from 'react';
|
|
2
|
+
import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
|
|
3
3
|
import { SCROLLBAR_SIZE, MIN_SCROLLBAR_SIZE } from '../utils/constants.js';
|
|
4
4
|
import { calculateScrollbarMetrics } from '../utils/tableCalculations.js';
|
|
5
5
|
import 'zmdms-utils';
|
|
@@ -191,103 +191,211 @@ var useSelectionBoundaryScroll = function (params) {
|
|
|
191
191
|
var containerRef = params.containerRef, isSelecting = params.isSelecting,
|
|
192
192
|
// scrollState,
|
|
193
193
|
setScrollState = params.setScrollState, maxScrollTop = params.maxScrollTop, maxScrollLeft = params.maxScrollLeft, onScroll = params.onScroll, getCellFromPosition = params.getCellFromPosition, updateSelection = params.updateSelection, columnRenderInfos = params.columnRenderInfos;
|
|
194
|
-
var
|
|
194
|
+
var scrollRafRef = useRef(null);
|
|
195
195
|
var currentMousePosRef = useRef(null);
|
|
196
|
+
var lastCellRef = useRef(null);
|
|
197
|
+
var scrollVelocityRef = useRef({
|
|
198
|
+
deltaX: 0,
|
|
199
|
+
deltaY: 0,
|
|
200
|
+
});
|
|
201
|
+
// 状态更新去抖:避免频繁的状态更新
|
|
202
|
+
var stateUpdateRafRef = useRef(null);
|
|
203
|
+
var pendingStateUpdateRef = useRef(null);
|
|
204
|
+
// 缓存当前的滚动状态,避免频繁读取
|
|
205
|
+
var currentScrollStateRef = useRef({ scrollLeft: 0, scrollTop: 0 });
|
|
206
|
+
// 使用 ref 保存最新的函数引用,避免闭包问题
|
|
207
|
+
var setScrollStateRef = useRef(setScrollState);
|
|
208
|
+
var onScrollRef = useRef(onScroll);
|
|
209
|
+
var getCellFromPositionRef = useRef(getCellFromPosition);
|
|
210
|
+
var updateSelectionRef = useRef(updateSelection);
|
|
211
|
+
var columnRenderInfosRef = useRef(columnRenderInfos);
|
|
212
|
+
// 更新 ref 中的函数引用
|
|
213
|
+
useEffect(function () {
|
|
214
|
+
setScrollStateRef.current = setScrollState;
|
|
215
|
+
onScrollRef.current = onScroll;
|
|
216
|
+
getCellFromPositionRef.current = getCellFromPosition;
|
|
217
|
+
updateSelectionRef.current = updateSelection;
|
|
218
|
+
columnRenderInfosRef.current = columnRenderInfos;
|
|
219
|
+
});
|
|
220
|
+
// 同步当前滚动状态到 ref
|
|
221
|
+
useEffect(function () {
|
|
222
|
+
// 通过 setScrollState 的返回值来获取当前状态(不触发状态更新)
|
|
223
|
+
var currentState;
|
|
224
|
+
setScrollStateRef.current(function (prev) {
|
|
225
|
+
currentState = prev;
|
|
226
|
+
return prev; // 不修改状态,只读取
|
|
227
|
+
});
|
|
228
|
+
if (currentState) {
|
|
229
|
+
currentScrollStateRef.current = {
|
|
230
|
+
scrollLeft: currentState.scrollLeft,
|
|
231
|
+
scrollTop: currentState.scrollTop,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
});
|
|
196
235
|
var SCROLL_BOUNDARY_SIZE = 50; // 触发滚动的边界距离
|
|
197
|
-
var SCROLL_SPEED =
|
|
198
|
-
//
|
|
199
|
-
var
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
236
|
+
var SCROLL_SPEED = 6; // 每次滚动的距离(进一步降低以减少频率)
|
|
237
|
+
// 防抖:避免鼠标移动时过度频繁地触发边界检测
|
|
238
|
+
var boundaryCheckThrottleRef = useRef(0);
|
|
239
|
+
// 批量状态更新函数:减少重新渲染次数
|
|
240
|
+
var batchUpdateScrollState = useCallback(function (newScrollLeft, newScrollTop) {
|
|
241
|
+
// 立即更新缓存状态
|
|
242
|
+
currentScrollStateRef.current = {
|
|
243
|
+
scrollLeft: newScrollLeft,
|
|
244
|
+
scrollTop: newScrollTop,
|
|
245
|
+
};
|
|
246
|
+
// 保存待更新的状态
|
|
247
|
+
pendingStateUpdateRef.current = {
|
|
248
|
+
scrollLeft: newScrollLeft,
|
|
249
|
+
scrollTop: newScrollTop,
|
|
250
|
+
};
|
|
251
|
+
// 如果已经有待处理的更新,直接返回
|
|
252
|
+
if (stateUpdateRafRef.current !== null) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// 延迟到下一个渲染周期批量更新
|
|
256
|
+
stateUpdateRafRef.current = requestAnimationFrame(function () {
|
|
257
|
+
var pendingUpdate = pendingStateUpdateRef.current;
|
|
258
|
+
if (pendingUpdate) {
|
|
259
|
+
setScrollStateRef.current(function (prev) {
|
|
260
|
+
if (prev.scrollLeft !== pendingUpdate.scrollLeft ||
|
|
261
|
+
prev.scrollTop !== pendingUpdate.scrollTop) {
|
|
262
|
+
// 延迟调用 onScroll 回调,避免阻塞滚动
|
|
263
|
+
setTimeout(function () {
|
|
264
|
+
var _a;
|
|
265
|
+
(_a = onScrollRef.current) === null || _a === void 0 ? void 0 : _a.call(onScrollRef, pendingUpdate.scrollLeft, pendingUpdate.scrollTop);
|
|
266
|
+
}, 0);
|
|
267
|
+
return __assign(__assign({}, prev), { scrollLeft: pendingUpdate.scrollLeft, scrollTop: pendingUpdate.scrollTop });
|
|
268
|
+
}
|
|
269
|
+
return prev;
|
|
270
|
+
});
|
|
221
271
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
272
|
+
// 清理状态
|
|
273
|
+
stateUpdateRafRef.current = null;
|
|
274
|
+
pendingStateUpdateRef.current = null;
|
|
275
|
+
});
|
|
276
|
+
}, []);
|
|
277
|
+
// 检查边界滚动
|
|
278
|
+
var checkBoundaryScroll = useCallback(function (mouseX, mouseY) {
|
|
279
|
+
if (!containerRef.current || !isSelecting)
|
|
280
|
+
return;
|
|
281
|
+
// 节流:限制边界检测频率(每16ms最多执行一次,约60fps)
|
|
282
|
+
var now = performance.now();
|
|
283
|
+
if (now - boundaryCheckThrottleRef.current < 16) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
boundaryCheckThrottleRef.current = now;
|
|
287
|
+
var rect = containerRef.current.getBoundingClientRect();
|
|
288
|
+
var containerWidth = rect.width;
|
|
289
|
+
var containerHeight = rect.height;
|
|
290
|
+
var scrollDeltaX = 0;
|
|
291
|
+
var scrollDeltaY = 0;
|
|
292
|
+
// 检查水平边界
|
|
293
|
+
if (mouseX < SCROLL_BOUNDARY_SIZE) {
|
|
294
|
+
// 接近左边界,向左滚动
|
|
295
|
+
scrollDeltaX = -SCROLL_SPEED;
|
|
296
|
+
}
|
|
297
|
+
else if (mouseX > containerWidth - SCROLL_BOUNDARY_SIZE) {
|
|
298
|
+
// 接近右边界,向右滚动
|
|
299
|
+
scrollDeltaX = SCROLL_SPEED;
|
|
300
|
+
}
|
|
301
|
+
// 检查垂直边界
|
|
302
|
+
if (mouseY < SCROLL_BOUNDARY_SIZE) {
|
|
303
|
+
// 接近顶部边界,向上滚动
|
|
304
|
+
scrollDeltaY = -SCROLL_SPEED;
|
|
305
|
+
}
|
|
306
|
+
else if (mouseY > containerHeight - SCROLL_BOUNDARY_SIZE) {
|
|
307
|
+
// 接近底部边界,向下滚动
|
|
308
|
+
scrollDeltaY = SCROLL_SPEED;
|
|
309
|
+
}
|
|
310
|
+
// 保存当前鼠标位置和滚动速度
|
|
311
|
+
currentMousePosRef.current = { x: mouseX, y: mouseY };
|
|
312
|
+
scrollVelocityRef.current = {
|
|
313
|
+
deltaX: scrollDeltaX,
|
|
314
|
+
deltaY: scrollDeltaY,
|
|
315
|
+
};
|
|
316
|
+
// 如果需要滚动
|
|
317
|
+
if (scrollDeltaX !== 0 || scrollDeltaY !== 0) {
|
|
318
|
+
// 清除之前的动画帧
|
|
319
|
+
if (scrollRafRef.current) {
|
|
320
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
225
321
|
}
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
clearInterval(scrollIntervalRef.current);
|
|
322
|
+
// 开始持续滚动(优化版本)
|
|
323
|
+
var performScroll_1 = function () {
|
|
324
|
+
var _a;
|
|
325
|
+
var velocity = scrollVelocityRef.current;
|
|
326
|
+
if (velocity.deltaX === 0 && velocity.deltaY === 0) {
|
|
327
|
+
return; // 停止滚动
|
|
233
328
|
}
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
329
|
+
// 获取当前滚动状态(从缓存中读取,避免触发状态更新)
|
|
330
|
+
var currentState = currentScrollStateRef.current;
|
|
331
|
+
var newScrollLeft = Math.max(0, Math.min(maxScrollLeft, currentState.scrollLeft + velocity.deltaX));
|
|
332
|
+
var newScrollTop = Math.max(0, Math.min(maxScrollTop, currentState.scrollTop + velocity.deltaY));
|
|
333
|
+
// 只有在位置真正发生变化时才更新
|
|
334
|
+
if (newScrollLeft !== currentState.scrollLeft ||
|
|
335
|
+
newScrollTop !== currentState.scrollTop) {
|
|
336
|
+
// 使用批量更新机制
|
|
337
|
+
batchUpdateScrollState(newScrollLeft, newScrollTop);
|
|
338
|
+
// 优化的框选更新:减少不必要的计算
|
|
339
|
+
if (getCellFromPositionRef.current &&
|
|
340
|
+
updateSelectionRef.current &&
|
|
341
|
+
columnRenderInfosRef.current &&
|
|
342
|
+
currentMousePosRef.current) {
|
|
343
|
+
var _b = currentMousePosRef.current, x = _b.x, y = _b.y;
|
|
344
|
+
// 添加位置计算的缓存,避免重复计算
|
|
345
|
+
try {
|
|
346
|
+
var cell = getCellFromPositionRef.current(x, y);
|
|
347
|
+
// 只有当单元格位置发生变化时才更新框选
|
|
348
|
+
if (cell &&
|
|
349
|
+
(!lastCellRef.current ||
|
|
350
|
+
lastCellRef.current.row !== cell.row ||
|
|
351
|
+
lastCellRef.current.col !== cell.col)) {
|
|
352
|
+
var isSelectionColumn = ((_a = columnRenderInfosRef.current[cell.col]) === null || _a === void 0 ? void 0 : _a.column.key) ===
|
|
353
|
+
"__selection__";
|
|
354
|
+
if (!isSelectionColumn) {
|
|
355
|
+
updateSelectionRef.current(cell);
|
|
356
|
+
lastCellRef.current = cell;
|
|
256
357
|
}
|
|
257
358
|
}
|
|
258
|
-
return __assign(__assign({}, prev), { scrollLeft: newScrollLeft, scrollTop: newScrollTop });
|
|
259
359
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// 停止滚动
|
|
266
|
-
if (scrollIntervalRef.current) {
|
|
267
|
-
clearInterval(scrollIntervalRef.current);
|
|
268
|
-
scrollIntervalRef.current = null;
|
|
360
|
+
catch (error) {
|
|
361
|
+
// 如果计算单元格位置出错,静默处理,不影响滚动
|
|
362
|
+
console.warn("Cell position calculation error during boundary scroll:", error);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
269
365
|
}
|
|
366
|
+
// 继续滚动
|
|
367
|
+
scrollRafRef.current = requestAnimationFrame(performScroll_1);
|
|
368
|
+
};
|
|
369
|
+
scrollRafRef.current = requestAnimationFrame(performScroll_1);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
// 停止滚动
|
|
373
|
+
if (scrollRafRef.current) {
|
|
374
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
375
|
+
scrollRafRef.current = null;
|
|
270
376
|
}
|
|
271
|
-
|
|
377
|
+
scrollVelocityRef.current = { deltaX: 0, deltaY: 0 };
|
|
378
|
+
}
|
|
272
379
|
}, [
|
|
273
380
|
containerRef,
|
|
274
381
|
isSelecting,
|
|
275
|
-
setScrollState,
|
|
276
382
|
maxScrollTop,
|
|
277
383
|
maxScrollLeft,
|
|
278
|
-
|
|
279
|
-
getCellFromPosition,
|
|
280
|
-
updateSelection,
|
|
281
|
-
columnRenderInfos,
|
|
384
|
+
batchUpdateScrollState,
|
|
282
385
|
]);
|
|
283
386
|
// 停止边界滚动
|
|
284
|
-
var stopBoundaryScroll =
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
387
|
+
var stopBoundaryScroll = useCallback(function () {
|
|
388
|
+
if (scrollRafRef.current) {
|
|
389
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
390
|
+
scrollRafRef.current = null;
|
|
391
|
+
}
|
|
392
|
+
if (stateUpdateRafRef.current) {
|
|
393
|
+
cancelAnimationFrame(stateUpdateRafRef.current);
|
|
394
|
+
stateUpdateRafRef.current = null;
|
|
395
|
+
}
|
|
396
|
+
scrollVelocityRef.current = { deltaX: 0, deltaY: 0 };
|
|
397
|
+
pendingStateUpdateRef.current = null;
|
|
398
|
+
lastCellRef.current = null; // 重置缓存的单元格位置
|
|
291
399
|
}, []);
|
|
292
400
|
// 当框选结束时停止滚动
|
|
293
401
|
useEffect(function () {
|
|
@@ -295,11 +403,14 @@ var useSelectionBoundaryScroll = function (params) {
|
|
|
295
403
|
stopBoundaryScroll();
|
|
296
404
|
}
|
|
297
405
|
}, [isSelecting, stopBoundaryScroll]);
|
|
298
|
-
//
|
|
406
|
+
// 组件卸载时清理动画帧
|
|
299
407
|
useEffect(function () {
|
|
300
408
|
return function () {
|
|
301
|
-
if (
|
|
302
|
-
|
|
409
|
+
if (scrollRafRef.current) {
|
|
410
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
411
|
+
}
|
|
412
|
+
if (stateUpdateRafRef.current) {
|
|
413
|
+
cancelAnimationFrame(stateUpdateRafRef.current);
|
|
303
414
|
}
|
|
304
415
|
};
|
|
305
416
|
}, []);
|
|
@@ -289,12 +289,21 @@ interface ITableRefHandel {
|
|
|
289
289
|
*/
|
|
290
290
|
clearErrorClass?: () => void;
|
|
291
291
|
/**
|
|
292
|
-
*
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
* 滚动到指定位置
|
|
293
|
+
* 虚拟滚动时:使用 virtuallist-antd 的 scrollTo 方法,需要传 row、y、vid
|
|
294
|
+
* 普通滚动时:操作 DOM,可以传 y、x 或 index
|
|
295
|
+
* @param options.row - 虚拟滚动时滚动到第几行
|
|
296
|
+
* @param options.y - 垂直滚动的像素值
|
|
297
|
+
* @param options.x - 水平滚动的像素值
|
|
298
|
+
* @param options.vid - 虚拟滚动的唯一标识符
|
|
299
|
+
* @param options.index - 滚动到指定行索引(普通滚动)
|
|
300
|
+
*/
|
|
301
|
+
scrollTo?: (options: {
|
|
302
|
+
row?: number;
|
|
303
|
+
y?: number;
|
|
304
|
+
x?: number;
|
|
305
|
+
vid?: string;
|
|
306
|
+
index?: number;
|
|
298
307
|
}) => void;
|
|
299
308
|
/**
|
|
300
309
|
* 重置
|
package/dist/es/table/table.js
CHANGED
|
@@ -19,7 +19,7 @@ import useSummary from './useSummary.js';
|
|
|
19
19
|
import useInnerPagination, { getInnerIndex } from './useInnerPagination.js';
|
|
20
20
|
import { useScuRfresh, useCustomSort, useCalcScrollY, useEditChange, useMoveRowChange, useAddAndDelChange, useCustomFilter, useAutoMerge } from './hooks.js';
|
|
21
21
|
import { HTML5Backend } from '../node_modules/react-dnd-html5-backend/dist/index.js';
|
|
22
|
-
import {
|
|
22
|
+
import { scrollTo, VList } from '../node_modules/virtuallist-antd/dist/index.es.js';
|
|
23
23
|
import useTableValidate, { tableValidate } from './useTableValidate.js';
|
|
24
24
|
import TitleDirectionColumn from './components/TitleDirectionColumn.js';
|
|
25
25
|
import { useExcelExport } from './excel.js';
|
|
@@ -193,6 +193,43 @@ var Table = function (props) {
|
|
|
193
193
|
});
|
|
194
194
|
// 表格验证
|
|
195
195
|
var _y = useTableValidate(), tableRef = _y.tableRef, getCurrentTable = _y.getCurrentTable, clearErrorClass = _y.clearErrorClass;
|
|
196
|
+
// 滚动条控制方法
|
|
197
|
+
var scrollToPosition = useMemoizedFn(function (options) {
|
|
198
|
+
var _a;
|
|
199
|
+
// 如果是虚拟滚动,使用 virtuallist-antd 的 scrollTo 方法
|
|
200
|
+
if (virtualKey && options.vid) {
|
|
201
|
+
scrollTo({
|
|
202
|
+
row: options.row || 0,
|
|
203
|
+
y: options.y || 0,
|
|
204
|
+
vid: options.vid || virtualKey,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// 普通滚动,操作 DOM
|
|
209
|
+
var tableBody = (_a = tableRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(".ant-table-body");
|
|
210
|
+
if (tableBody) {
|
|
211
|
+
// 如果指定了 y 值,直接滚动到指定位置
|
|
212
|
+
if (typeof options.y === "number") {
|
|
213
|
+
tableBody.scrollTop = options.y;
|
|
214
|
+
}
|
|
215
|
+
// 如果指定了 x 值,直接滚动到指定位置
|
|
216
|
+
if (typeof options.x === "number") {
|
|
217
|
+
tableBody.scrollLeft = options.x;
|
|
218
|
+
}
|
|
219
|
+
// 如果指定了 index,滚动到指定行
|
|
220
|
+
if (typeof options.index === "number") {
|
|
221
|
+
var rows = tableBody.querySelectorAll(".ant-table-row");
|
|
222
|
+
var targetRow = rows[options.index];
|
|
223
|
+
if (targetRow) {
|
|
224
|
+
targetRow.scrollIntoView({
|
|
225
|
+
behavior: "smooth",
|
|
226
|
+
block: "center",
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
});
|
|
196
233
|
// 虚拟滚动选项
|
|
197
234
|
var vComponents = useMemo(function () {
|
|
198
235
|
if (virtualKey) {
|
|
@@ -307,9 +344,13 @@ var Table = function (props) {
|
|
|
307
344
|
}); },
|
|
308
345
|
/** 清除错误样式 */
|
|
309
346
|
clearErrorClass: clearErrorClass,
|
|
310
|
-
/**
|
|
311
|
-
|
|
312
|
-
|
|
347
|
+
/**
|
|
348
|
+
* 滚动到指定位置
|
|
349
|
+
* 虚拟滚动时使用 virtuallist-antd 的 scrollTo 方法
|
|
350
|
+
* 普通滚动时操作 DOM
|
|
351
|
+
*/
|
|
352
|
+
scrollTo: function (options) {
|
|
353
|
+
scrollToPosition(options);
|
|
313
354
|
},
|
|
314
355
|
/** 动态列配置重置 */
|
|
315
356
|
onResetDynamicList: function () {
|