Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions packages/components/table/BaseTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
lazyLoad,
pagination,
} = props;

const borderWidth = props.bordered ? 1 : 0;

const tableRef = useRef<HTMLDivElement>(null);
const tableElmRef = useRef<HTMLTableElement>(null);
const bottomContentRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -105,7 +108,6 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
updateColumnFixedShadow,
getThWidthList,
updateThWidthList,
addTableResizeObserver,
updateTableAfterColumnResize,
} = useFixed(props, finalColumns, {
paginationAffixRef,
Expand Down Expand Up @@ -156,9 +158,12 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
if (!bordered) return;
const bottomRect = bottomContentRef.current?.getBoundingClientRect();
const paginationRect = paginationRef.current?.getBoundingClientRect();
const bottom = (bottomRect?.height || 0) + (paginationRect?.height || 0);
let bottom = (bottomRect?.height || 0) + (paginationRect?.height || 0);
if (props.horizontalScrollAffixedBottom) {
bottom -= scrollbarWidth + borderWidth;
}
setDividerBottom(bottom);
}, [bottomContentRef, paginationRef, bordered]);
}, [bottomContentRef, paginationRef, bordered, props.horizontalScrollAffixedBottom, scrollbarWidth, borderWidth]);

useEffect(() => {
setUseFixedTableElmRef(tableElmRef.current);
Expand Down Expand Up @@ -294,12 +299,6 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [tableContentRef]);

useEffect(
() => addTableResizeObserver(tableRef.current),
// eslint-disable-next-line react-hooks/exhaustive-deps
[tableRef],
);

const newData = isPaginateData ? dataSource : data;

const renderColGroup = (isFixedHeader = true) => (
Expand Down Expand Up @@ -353,9 +352,6 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
props.size,
];

// 多级表头左边线缺失
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;
Expand All @@ -376,7 +372,7 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
const affixedHeader = Boolean((headerAffixedTop || virtualConfig.isVirtualScroll) && tableWidth.current) && (
<div
ref={affixHeaderRef}
style={{ width: `${tableWidth.current - affixedLeftBorder - barWidth}px`, opacity: headerOpacity }}
style={{ width: `${tableWidth.current - borderWidth}px`, opacity: headerOpacity }}
className={classNames([
'scrollbar',
{
Expand Down Expand Up @@ -446,7 +442,7 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
>
<div
ref={affixFooterRef}
style={{ width: `${tableWidth.current - affixedLeftBorder}px`, opacity: Number(showAffixFooter) }}
style={{ width: `${tableWidth.current - borderWidth}px`, opacity: Number(showAffixFooter) }}
className={classNames([
'scrollbar',
{ [tableBaseClass.affixedFooterElm]: props.footerAffixedBottom || virtualConfig.isVirtualScroll },
Expand Down Expand Up @@ -632,7 +628,7 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
tableWidth,
tableElmWidth,
affixHeaderRef,
affixedLeftBorder,
borderWidth,
tableElmClasses,
tableElementStyles,
columns,
Expand All @@ -657,7 +653,7 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
tableElementStyles,
tableElmWidth,
affixFooterRef,
affixedLeftBorder,
borderWidth,
bordered,
isWidthOverflow,
scrollbarWidth,
Expand Down
2 changes: 1 addition & 1 deletion packages/components/table/TBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export default function TBody(props: TableBodyProps) {

const [global, t] = useLocaleReceiver('table');

const { skipSpansMap } = useRowspanAndColspan(data, columns, rowKey, props.rowspanAndColspan);
const { skipSpansMap } = useRowspanAndColspan(renderData, columns, rowKey, props.rowspanAndColspan);
const isSkipSnapsMapNotFinish = Boolean(props.rowspanAndColspan && !skipSpansMap.size);

const { tableFullRowClasses, tableBaseClass } = allTableClasses;
Expand Down
77 changes: 34 additions & 43 deletions packages/components/table/hooks/useFixed.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { type MutableRefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { get, pick, xorWith } from 'lodash-es';
import { type MutableRefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';

import log from '@tdesign/common-js/log/index';
import { getScrollbarWidthWithCSS } from '@tdesign/common-js/utils/getScrollbarWidth';
import { getIEVersion } from '@tdesign/common-js/utils/helper';
import { off, on } from '../../_util/listener';
import useDebounce from '../../hooks/useDebounce';
import useDeepEffect from '../../hooks/useDeepEffect';
import usePrevious from '../../hooks/usePrevious';
import { isLessThanIE11OrNotHaveResizeObserver, resizeObserverElement } from '../utils';
import { resizeObserverElement } from '../utils';

import type { AffixRef } from '../../affix';
import type { ClassName, Styles } from '../../common';
Expand Down Expand Up @@ -369,10 +368,13 @@ export default function useFixed(
};

const updateTableWidth = () => {
const rect = tableContentRef.current?.getBoundingClientRect?.();
const tRef = tableContentRef.current;
const rect = tRef?.getBoundingClientRect?.();
if (!rect) return;
// 存在纵向滚动条,且固定表头时,需去除滚动条宽度
const reduceWidth = isFixedHeader ? scrollbarWidth : 0;
// 直接从 DOM 判断是否存在纵向溢出,避免依赖异步的 React state
const isCurrentHeightOverflow = tRef.scrollHeight > tRef.clientHeight;
// 去除滚动条宽度
const reduceWidth = isCurrentHeightOverflow ? scrollbarWidth : 0;
tableWidth.current = rect.width - reduceWidth - (props.bordered ? 1 : 0);
const elmRect = tableElmRef?.current?.getBoundingClientRect();
if (elmRect?.width) {
Expand Down Expand Up @@ -488,20 +490,6 @@ export default function useFixed(
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isFixedColumn, columns, tableContentRef]);

// 使用防抖函数,避免频繁触发
const updateFixedHeaderByUseDebounce = useDebounce(() => {
updateFixedHeader();
}, 30);

/**
* 通过监测表格大小变化,来调用 updateFixedHeader 修改状态
*/
useEffect(() => {
if (tableContentRef.current) {
return resizeObserverElement(tableContentRef.current, updateFixedHeaderByUseDebounce);
}
}, [updateFixedHeaderByUseDebounce]);

useDeepEffect(updateFixedHeader, [maxHeight, data, columns, bordered, tableContentRef]);

useDeepEffect(() => {
Expand Down Expand Up @@ -540,25 +528,14 @@ export default function useFixed(
}
};

const onResize = useDebounce(() => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

使用 debounce 会导致 resize 时肉眼可见的闪烁

refreshTable();
}, 30);

function addTableResizeObserver(tableElement: HTMLDivElement) {
/**
* IE 11 以下使用 window resize;IE 11 以上使用 ResizeObserver
* 抽离相关判断为单独的方法
*/
if (isLessThanIE11OrNotHaveResizeObserver()) return;
off(window, 'resize', onResize);
if (!tableElmWidth.current) return;
// 抽离 resize 为单独的方法,通过回调来执行操作
return resizeObserverElement(tableElement, () => {
refreshTable();
});
}

useEffect(() => {
if (!tableContentRef.current) return;
// IE 11 以上使用 ResizeObserver
return resizeObserverElement(tableContentRef.current, refreshTable);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useDeepEffect(() => {
const scrollWidth = getScrollbarWidthWithCSS();
setScrollbarWidth(scrollWidth);

Expand All @@ -567,20 +544,35 @@ export default function useFixed(
const hasResizeObserver = hasWindow && typeof window.ResizeObserver !== 'undefined';
updateTableWidth();
updateThWidthListHandler();
// IE 11 以下使用 window resize;IE 11 以上使用 ResizeObserver
// IE 11 以下使用 window resize
if ((isWatchResize && getIEVersion() < 11) || !hasResizeObserver) {
on(window, 'resize', onResize);
on(window, 'resize', refreshTable);
}

return () => {
if ((isWatchResize && getIEVersion() < 11) || !hasResizeObserver) {
if (typeof window !== 'undefined') {
off(window, 'resize', onResize);
off(window, 'resize', refreshTable);
}
}
};
}, [isFixedColumn, isFixedHeader, isWidthOverflow, scrollbarWidth, notNeedThWidthList, data]);

useEffect(() => {
// 针对表格放在 Dialog 等有动画效果元素里的场景
const tableContent = tableContentRef.current;
if (!tableContent) return;
const onAnimationEnd = (e: AnimationEvent) => {
const target = e.target as HTMLElement;
if (!target || !target.contains(tableContent)) return;
refreshTable();
};
on(document, 'animationend', onAnimationEnd, { capture: true });
return () => {
off(document, 'animationend', onAnimationEnd, { capture: true });
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isFixedColumn]);
}, []);

const updateTableAfterColumnResize = () => {
updateFixedStatus();
Expand Down Expand Up @@ -608,7 +600,6 @@ export default function useFixed(
setUseFixedTableElmRef,
getThWidthList,
updateThWidthList,
addTableResizeObserver,
updateTableAfterColumnResize,
};
}
7 changes: 4 additions & 3 deletions packages/components/table/hooks/useRowspanAndColspan.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useEffect, useState } from 'react';
import { useState } from 'react';
import { get } from 'lodash-es';
import log from '@tdesign/common-js/log/index';
import { BaseTableCellParams, BaseTableCol, TableRowData, TableRowspanAndColspanFunc } from '../type';
import useIsomorphicLayoutEffect from '../../hooks/useLayoutEffect';
import type { BaseTableCellParams, BaseTableCol, TableRowData, TableRowspanAndColspanFunc } from '../type';

export interface SkipSpansValue {
colspan?: number;
Expand Down Expand Up @@ -80,7 +81,7 @@ export default function useRowspanAndColspan(
return map;
};

useEffect(() => {
useIsomorphicLayoutEffect(() => {
if (!rowspanAndColspan) return;
skipSpansMap.clear();
const result = getSkipSpansMap(data, columns, rowspanAndColspan);
Expand Down
Loading