Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
60 changes: 60 additions & 0 deletions packages/components/hooks/useDomRefMount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useCallback, useRef } from 'react';

function useDomRefMount<T extends HTMLElement = HTMLElement>(ref: React.MutableRefObject<T | null>) {
const callbacks = useRef<Array<(node: T) => void>>([]);
const unmountCallbacks = useRef<Array<() => void>>([]);

const onMount = useCallback(
(nodeOrCallback: T | ((node: T) => void)) => {
// 如果传入的是函数,则注册回调
if (typeof nodeOrCallback === 'function') {
callbacks.current.push(nodeOrCallback);
return;
}

// 否则是 ref 挂载
const node = nodeOrCallback as T;
const prevNode = ref?.current;

// 更新 ref
if (ref) {
// eslint-disable-next-line no-param-reassign
ref.current = node;
}

// 如果是新挂载(从 null 变为有值),触发所有挂载回调
if (node && !prevNode) {
callbacks.current.forEach((callback) => {
callback(node);
});
}

// 如果是卸载(从有值变为 null),触发所有卸载回调
if (!node && prevNode) {
unmountCallbacks.current.forEach((callback) => {
callback();
});
}

return node;
},
[], // eslint-disable-line react-hooks/exhaustive-deps
);

const onUnmount = useCallback((callback: () => void) => {
unmountCallbacks.current.push(callback);
}, []);

const clearCallbacks = useCallback(() => {
callbacks.current = [];
unmountCallbacks.current = [];
}, []);

return {
onMount,
onUnmount,
clearCallbacks,
};
}

export default useDomRefMount;
17 changes: 10 additions & 7 deletions packages/components/table/BaseTable.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { forwardRef, RefAttributes, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import classNames from 'classnames';
import { pick } from 'lodash-es';

import log from '@tdesign/common-js/log/index';
import { getIEVersion } from '@tdesign/common-js/utils/helper';
import Affix, { type AffixRef } from '../affix';
import useDefaultProps from '../hooks/useDefaultProps';
import useDomRefMount from '../hooks/useDomRefMount';
import useElementLazyRender from '../hooks/useElementLazyRender';
import useVirtualScroll from '../hooks/useVirtualScroll';
import Loading from '../loading';
Expand Down Expand Up @@ -52,11 +54,12 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
const tableRef = useRef<HTMLDivElement>(null);
const tableElmRef = useRef<HTMLTableElement>(null);
const bottomContentRef = useRef<HTMLDivElement>(null);

const [tableFootHeight, setTableFootHeight] = useState(0);
const [dividerBottom, setDividerBottom] = useState(0);

const allTableClasses = useClassName();
const { classPrefix, virtualScrollClasses, tableLayoutClasses, tableBaseClass, tableColFixedClasses } =
allTableClasses;
useClassName();
// 表格基础样式类
const { tableClasses, sizeClassNames, tableContentStyles, tableElementStyles } = useStyle(props);
const { isMultipleHeader, spansAndLeafNodes, thList } = useTableHeader({ columns: props.columns });
Expand Down Expand Up @@ -114,6 +117,8 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
footerBottomAffixRef,
});

const { onMount: onAffixHeaderMount } = useDomRefMount(affixHeaderRef);

const { dataSource, innerPagination, isPaginateData, renderPagination } = usePagination(props, tableContentRef);

// 列宽拖拽逻辑
Expand Down Expand Up @@ -151,7 +156,6 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
[isFixedHeader, isMultipleHeader, isWidthOverflow, props.bordered],
);

const [dividerBottom, setDividerBottom] = useState(0);
useEffect(() => {
if (!bordered) return;
const bottomRect = bottomContentRef.current?.getBoundingClientRect();
Expand Down Expand Up @@ -255,7 +259,7 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
const scrollColumnIntoView = (colKey: string) => {
if (!tableContentRef.current) return;
const thDom = tableContentRef.current.querySelector(`th[data-colkey="${colKey}"]`);
const fixedThDom = tableContentRef.current.querySelectorAll('th.t-table__cell--fixed-left');
const fixedThDom = tableContentRef.current.querySelectorAll(`th.${classPrefix}-table__cell--fixed-left`);
let totalWidth = 0;
for (let i = 0, len = fixedThDom.length; i < len; i++) {
totalWidth += fixedThDom[i].getBoundingClientRect().width;
Expand All @@ -272,6 +276,7 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
tableHtmlElement: tableElmRef.current,
tableContentElement: tableContentRef.current,
affixHeaderElement: affixHeaderRef.current,
onAffixHeaderMount,
refreshTable,
scrollToElement: virtualConfig.scrollToElement,
scrollColumnIntoView,
Expand Down Expand Up @@ -375,7 +380,7 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
};
const affixedHeader = Boolean((headerAffixedTop || virtualConfig.isVirtualScroll) && tableWidth.current) && (
<div
ref={affixHeaderRef}
ref={onAffixHeaderMount}
style={{ width: `${tableWidth.current - affixedLeftBorder - barWidth}px`, opacity: headerOpacity }}
className={classNames([
'scrollbar',
Expand Down Expand Up @@ -489,7 +494,6 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
tableContentRef,
tableWidth,
isWidthOverflow,
allTableClasses,
rowKey,
scroll: props.scroll,
cellEmptyContent: props.cellEmptyContent,
Expand Down Expand Up @@ -537,7 +541,6 @@ const BaseTable = forwardRef<BaseTableRef, BaseTableProps>((originalProps, ref)
),
// eslint-disable-next-line
[
allTableClasses,
tableBodyProps.ellipsisOverlayClassName,
tableBodyProps.rowAndColFixedPosition,
tableBodyProps.showColumnShadow,
Expand Down
8 changes: 4 additions & 4 deletions packages/components/table/TBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
import React, { type CSSProperties, type MutableRefObject, type ReactNode, useMemo } from 'react';
import classNames from 'classnames';
import { camelCase, get, pick } from 'lodash-es';

import { useLocaleReceiver } from '../locale/LocalReceiver';
import { TableClassName } from './hooks/useClassName';
import useClassName from './hooks/useClassName';
import useRowspanAndColspan from './hooks/useRowspanAndColspan';
import TR, { ROW_LISTENERS, TABLE_PROPS, type TrProps } from './TR';

Expand All @@ -25,7 +26,6 @@ export interface TableBodyProps extends BaseTableProps {
isWidthOverflow?: boolean;
virtualConfig: VirtualScrollConfig;
pagination?: PaginationProps;
allTableClasses?: TableClassName;
handleRowMounted?: (params: RowMountedParams) => void;
}

Expand Down Expand Up @@ -74,7 +74,7 @@ const trProperties = [

export default function TBody(props: TableBodyProps) {
// 如果不是变量复用,没必要对每一个参数进行解构(解构过程需要单独的内存空间存储临时变量)
const { data, columns, rowKey, firstFullRow, lastFullRow, virtualConfig, allTableClasses } = props;
const { data, columns, rowKey, firstFullRow, lastFullRow, virtualConfig } = props;

const { isVirtualScroll } = virtualConfig;
const renderData = isVirtualScroll ? virtualConfig.visibleData : data;
Expand All @@ -84,7 +84,7 @@ export default function TBody(props: TableBodyProps) {
const { skipSpansMap } = useRowspanAndColspan(data, columns, rowKey, props.rowspanAndColspan);
const isSkipSnapsMapNotFinish = Boolean(props.rowspanAndColspan && !skipSpansMap.size);

const { tableFullRowClasses, tableBaseClass } = allTableClasses;
const { tableFullRowClasses, tableBaseClass } = useClassName();
const tbodyClasses = useMemo(() => [tableBaseClass.body], [tableBaseClass.body]);
const hasFullRowConfig = useMemo(() => firstFullRow || lastFullRow, [firstFullRow, lastFullRow]);

Expand Down
19 changes: 6 additions & 13 deletions packages/components/table/hooks/useDragSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,21 +212,14 @@ export default function useDragSort(

// 注册拖拽事件
useEffect(() => {
if (!primaryTableRef || !primaryTableRef.current) return;
registerRowDragEvent(primaryTableRef.current?.tableElement);
registerColDragEvent(primaryTableRef.current?.tableHtmlElement);
/** 待表头节点准备完成后 */
const timer = setTimeout(() => {
if (primaryTableRef.current?.affixHeaderElement) {
registerColDragEvent(primaryTableRef.current.affixHeaderElement);
}
clearTimeout(timer);
if (!primaryTableRef.current) return;
registerRowDragEvent(primaryTableRef.current.tableElement);
registerColDragEvent(primaryTableRef.current.tableHtmlElement);
primaryTableRef.current.onAffixHeaderMount((el: HTMLDivElement) => {
registerColDragEvent(el);
});
return () => {
clearTimeout(timer);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [primaryTableRef, columns, dragSort, innerPagination]);
}, [columns, dragSort, innerPagination]);

return {
isRowDraggable,
Expand Down
Loading