From ab61e703b16bf45a2af7d872c2c8a059a032efd1 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Thu, 19 Mar 2026 14:32:12 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(data-grid):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E7=A9=BA=E6=95=B0=E6=8D=AE=E8=A1=A8Shift+=E6=BB=9A?= =?UTF-8?q?=E8=BD=AE=E6=A8=AA=E5=90=91=E6=BB=9A=E5=8A=A8=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 目标匹配:isTableDataAreaTarget 新增 .ant-table-placeholder 选择器覆盖空表占位元素 - 虚拟回退:虚拟模式下 rc-virtual-list-holder 不存在时,回退到手动滚动表头并同步外部滚动条 - 精准匹配:仅添加 .ant-table-placeholder,避免 .ant-table-header 导致有数据表头体滚动不同步 --- frontend/src/components/DataGrid.tsx | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/DataGrid.tsx b/frontend/src/components/DataGrid.tsx index 49c66cf..08e2e4e 100644 --- a/frontend/src/components/DataGrid.tsx +++ b/frontend/src/components/DataGrid.tsx @@ -3988,7 +3988,7 @@ const DataGrid: React.FC = ({ const element = target instanceof HTMLElement ? target : null; if (!element) return false; if (element.closest('.data-grid-external-horizontal-scroll')) return false; - return !!element.closest('.ant-table-body, .ant-table-content, .ant-table-cell, .ant-table-row, .ant-table-tbody'); + return !!element.closest('.ant-table-body, .ant-table-content, .ant-table-cell, .ant-table-row, .ant-table-tbody, .ant-table-placeholder'); }; const handleContainerHorizontalWheel = (event: WheelEvent) => { @@ -4002,6 +4002,31 @@ const DataGrid: React.FC = ({ // 自动同步 header scrollLeft。 // 仅需在状态更新后同步外部横向滚动条。 horizontalSyncSourceRef.current = 'table'; + + // 空数据回退:virtual-holder 不存在时,手动滚动表头 + const virtualHolder = container.querySelector('.rc-virtual-list-holder') as HTMLElement | null; + if (!virtualHolder) { + event.preventDefault(); + event.stopPropagation(); + const headerEl = container.querySelector('.ant-table-header') as HTMLElement | null; + const contentEl = container.querySelector('.ant-table-content') as HTMLElement | null; + const fallbackTargets = [headerEl, contentEl].filter((el): el is HTMLElement => el instanceof HTMLElement && el.scrollWidth > el.clientWidth + 1); + if (fallbackTargets.length > 0) { + fallbackTargets.forEach((target) => { + const max = Math.max(0, target.scrollWidth - target.clientWidth); + target.scrollLeft = Math.max(0, Math.min(max, target.scrollLeft + horizontalDelta)); + }); + lastTableScrollLeftRef.current = (fallbackTargets[0]).scrollLeft; + const externalScroll = externalHorizontalScrollRef.current; + if (externalScroll && Math.abs(externalScroll.scrollLeft - lastTableScrollLeftRef.current) > 1) { + externalScroll.scrollLeft = lastTableScrollLeftRef.current; + lastExternalScrollLeftRef.current = lastTableScrollLeftRef.current; + } + } + horizontalSyncSourceRef.current = ''; + return; + } + requestAnimationFrame(() => { const nextScrollLeft = readVirtualHorizontalOffset(container); lastTableScrollLeftRef.current = nextScrollLeft;