ProTable 自适应高度
本文来源:UmiJS PC 项目一:ProTable 高度设置虽然 ProTable 具备强大的配置功能,但在实际使用过程中,表格 - 掘金
useProTableSizeObserver.ts
useProTableSizeObserver.ts
ts
import { type MutableRefObject, useCallback, useEffect, useState } from 'react';
type ParentElement = Pick<HTMLElement, 'querySelector' | 'querySelectorAll'>;
/** 动态计算ProTable表格高度 */
export function useProTableSizeObserver<T>(
/** ProTable actionRef */
actionRef: MutableRefObject<T>,
options?: {
/** 一个页面存在多个table场景 */
wrapId?: string;
/** 屏幕高度:默认 100vh */
totalHeight?: string;
/** table 距离底部高度:默认 32px */
bottom?: number;
},
) {
const { totalHeight = '100vh', bottom = 32, wrapId } = options ?? {};
const [searchH, setSearchH] = useState<number>(80);
const getWrapSelector = useCallback(
(selector: string) => (wrapId ? `#${wrapId} .ant-pro-table ${selector}` : selector),
[wrapId],
);
const querySelector = useCallback(
(selector: string) => {
let parentElement: ParentElement = document;
if (wrapId) {
parentElement = document.getElementById(wrapId) as ParentElement;
}
const nodeList = Array.from(
parentElement.querySelectorAll<HTMLDivElement>(getWrapSelector(selector)),
);
if (nodeList.length > 0) {
return nodeList[nodeList.length - 1];
}
return undefined;
},
[getWrapSelector, wrapId],
);
const calcTableHeight = useCallback(
(tableHeader: HTMLDivElement, tableCardBody: HTMLDivElement) => {
let otherH = 0;
const { bottom: _bottom } = tableHeader.getBoundingClientRect();
const { paddingBlockEnd } = getComputedStyle(tableCardBody, null);
otherH = _bottom + parseInt(paddingBlockEnd);
const tablePagination = querySelector('.ant-table-pagination');
if (tablePagination) {
otherH += tablePagination?.offsetHeight ?? 24;
const { marginTop } = getComputedStyle(tablePagination, null);
otherH += parseInt(marginTop);
}
setSearchH(otherH);
},
[querySelector],
);
useEffect(() => {
if (!actionRef.current) return;
let observer: ResizeObserver | undefined;
let tableSearch: HTMLDivElement | undefined;
let tableHeader: HTMLDivElement | undefined;
let tableCardBody: HTMLDivElement | undefined;
setTimeout(() => {
tableSearch = querySelector('.ant-pro-table-search');
tableHeader = querySelector('.ant-table-header');
tableCardBody = querySelector('.ant-pro-card-body')!;
observer = new ResizeObserver(() => {
if (tableHeader && tableCardBody) calcTableHeight(tableHeader, tableCardBody);
});
if (tableSearch) observer.observe(tableSearch);
if (tableHeader) observer.observe(tableHeader);
if (tableCardBody) observer.observe(tableCardBody);
}, 100);
return () => {
if (observer) {
if (tableSearch) observer.unobserve(tableSearch);
if (tableHeader) observer.unobserve(tableHeader);
if (tableCardBody) observer.unobserve(tableCardBody);
}
};
}, [actionRef, calcTableHeight, querySelector]);
return {
// 冗余高度: 4px
tableScrollY: `calc(${totalHeight} - ${bottom}px - ${searchH}px - 4px)`,
};
}
使用方法
ts
// ...
const { tableScrollY } = useProTableSizeObserver(actionRef, { bottom: 50 });
return (<ProTable<TableDataType, Api.PageParams & TableSearchParams>
//...
scroll={{
y: tableScrollY,
}}
/>)