From 0cc866b80d06edfe3df47a537ccb0d97144a5e28 Mon Sep 17 00:00:00 2001 From: huangchen1031 Date: Wed, 26 Feb 2025 16:21:12 +0800 Subject: [PATCH 1/6] fix(Table): fix footer render when using virtual scroll (#3383) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(table): 修复虚拟滚动下的footer渲染问题 * chore: update snapshots * chore: update snapshots * chore: update snapshot --------- Co-authored-by: github-actions[bot] --- src/hooks/useVirtualScroll.ts | 6 +++++- src/table/BaseTable.tsx | 19 +++++++++++-------- src/table/TBody.tsx | 2 +- src/table/TFoot.tsx | 12 +++++++++--- .../__snapshots__/vitest-table.test.jsx.snap | 6 ++++++ test/snap/__snapshots__/csr.test.jsx.snap | 18 ++++++++++++------ test/snap/__snapshots__/ssr.test.jsx.snap | 10 +++++----- 7 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/hooks/useVirtualScroll.ts b/src/hooks/useVirtualScroll.ts index 00c319e2db..ceeefb1994 100644 --- a/src/hooks/useVirtualScroll.ts +++ b/src/hooks/useVirtualScroll.ts @@ -167,7 +167,11 @@ const useVirtualScroll = (container: MutableRefObject, params: UseV // 给数据添加下标 addIndexToData(data); - setScrollHeight(data.length * tScroll.rowHeight); + + const scrollTopHeightList = trScrollTopHeightList.current; + const lastIndex = scrollTopHeightList.length - 1; + setScrollHeight(scrollTopHeightList[lastIndex]); + const [startIndex, endIndex] = startAndEndIndex; const tmpData = data.slice(startIndex, endIndex); diff --git a/src/table/BaseTable.tsx b/src/table/BaseTable.tsx index 2d1d8bc197..8209b18cb7 100644 --- a/src/table/BaseTable.tsx +++ b/src/table/BaseTable.tsx @@ -332,19 +332,18 @@ const BaseTable = forwardRef((originalProps, ref) // 多级表头左边线缺失 const affixedLeftBorder = props.bordered ? 1 : 0; + // IE浏览器需要遮挡header吸顶滚动条,要减去getBoundingClientRect.height的滚动条高度4像素 + const IEHeaderWrap = getIEVersion() <= 11 ? 4 : 0; + const affixHeaderHeight = (affixHeaderRef.current?.getBoundingClientRect().height || 0) - IEHeaderWrap; /** * Affixed Header */ const renderFixedHeader = () => { if (!showHeader) return null; - // IE浏览器需要遮挡header吸顶滚动条,要减去getBoundingClientRect.height的滚动条高度4像素 - const IEHeaderWrap = getIEVersion() <= 11 ? 4 : 0; - const barWidth = isWidthOverflow ? scrollbarWidth : 0; - // const headerBarWidth = isFixedHeader ? scrollbarWidth : 0; - const affixHeaderHeight = (affixHeaderRef.current?.getBoundingClientRect().height || 0) - IEHeaderWrap; - const affixHeaderWrapHeight = affixHeaderHeight - barWidth; // 两类场景:1. 虚拟滚动,永久显示表头,直到表头消失在可视区域; 2. 表头吸顶,根据滚动情况判断是否显示吸顶表头 const headerOpacity = headerAffixedTop ? Number(showAffixHeader) : 1; + const barWidth = isWidthOverflow ? scrollbarWidth : 0; + const affixHeaderWrapHeight = affixHeaderHeight - barWidth; const affixHeaderWrapHeightStyle = { width: `${tableWidth.current}px`, height: `${affixHeaderWrapHeight}px`, @@ -409,7 +408,9 @@ const BaseTable = forwardRef((originalProps, ref) marginScrollbarWidth += 1; } // Hack: Affix 组件,marginTop 临时使用 负 margin 定位位置 - const affixedFooter = Boolean(props.footerAffixedBottom && props.footData?.length && tableWidth.current) && ( + const affixedFooter = Boolean( + (virtualConfig.isVirtualScroll || props.footerAffixedBottom) && props.footData?.length && tableWidth.current, + ) && ( ((originalProps, ref) pagination: innerPagination, }; - const translate = `translate(0, ${virtualConfig.scrollHeight}px)`; + const translate = `translate(0, ${virtualConfig.scrollHeight + affixHeaderHeight + tableFootHeight}px)`; const virtualStyle = { transform: translate, msTransform: translate, @@ -549,6 +550,7 @@ const BaseTable = forwardRef((originalProps, ref) thWidthList={thWidthList.current} footerSummary={props.footerSummary} rowspanAndColspanInFooter={props.rowspanAndColspanInFooter} + virtualScroll={virtualConfig.isVirtualScroll} > ), // eslint-disable-next-line @@ -563,6 +565,7 @@ const BaseTable = forwardRef((originalProps, ref) props.rowAttributes, props.rowClassName, props.footerSummary, + virtualConfig.isVirtualScroll, ], )} diff --git a/src/table/TBody.tsx b/src/table/TBody.tsx index c82d29b3a6..748ebcad00 100644 --- a/src/table/TBody.tsx +++ b/src/table/TBody.tsx @@ -1,5 +1,5 @@ import React, { CSSProperties, MutableRefObject, ReactNode, useMemo } from 'react'; -import { camelCase , get , pick } from 'lodash-es'; +import { camelCase, get, pick } from 'lodash-es'; import classNames from 'classnames'; import TR, { ROW_LISTENERS, TABLE_PROPS } from './TR'; import { useLocaleReceiver } from '../locale/LocalReceiver'; diff --git a/src/table/TFoot.tsx b/src/table/TFoot.tsx index 5852657be6..85b4b14cad 100644 --- a/src/table/TFoot.tsx +++ b/src/table/TFoot.tsx @@ -1,5 +1,5 @@ import React, { CSSProperties, useRef } from 'react'; -import { isFunction , get } from 'lodash-es'; +import { isFunction, get } from 'lodash-es'; import classNames from 'classnames'; import { BaseTableCellParams, RowspanColspan, TableRowData, TdBaseTableProps } from './type'; import { formatRowAttributes, formatRowClassNames } from './utils'; @@ -22,10 +22,11 @@ export interface TFootProps { thWidthList?: { [colKey: string]: number }; footerSummary?: TdBaseTableProps['footerSummary']; rowspanAndColspanInFooter: TdBaseTableProps['rowspanAndColspanInFooter']; + virtualScroll?: Boolean; } export default function TFoot(props: TFootProps) { - const { footData, columns, rowKey, footerSummary } = props; + const { footData, columns, rowKey, footerSummary, virtualScroll } = props; const tfooterRef = useRef(); const classnames = useClassName(); @@ -101,7 +102,12 @@ export default function TFoot(props: TFootProps) { // 都不存在,则不需要渲染 footer if (!footerSummary && (!props.footData || !props.footData.length)) return null; return ( - + // 虚拟滚动下,不显示 footer,但预留元素,用于高度计算 + {footerSummary && ( diff --git a/src/table/__tests__/__snapshots__/vitest-table.test.jsx.snap b/src/table/__tests__/__snapshots__/vitest-table.test.jsx.snap index 0c718f242c..3617fc4e4a 100644 --- a/src/table/__tests__/__snapshots__/vitest-table.test.jsx.snap +++ b/src/table/__tests__/__snapshots__/vitest-table.test.jsx.snap @@ -156,6 +156,7 @@ exports[`BaseTable Component > props.showHeader: BaseTable contains element \`th props.size is equal to large 1`] = ` props.size is equal to medium 1`] = ` props.size is equal to small 1`] = ` props.tableLayout is equal to auto 1`] = ` props.tableLayout is equal to fixed 1`] = ` csr test src/list/_example/virtual-scroll.tsx 1`] = style="height: 300px; position: relative;" >