可作为单独组建
// index.tsx
import { Table } from "antd";
import type { ColumnType, TableProps } from "antd/es/table";
import { FC, useEffect, useMemo, useRef, useState } from "react";
import ResizeTitle from "./resizeTitle";
const Index: FC<TableProps<any>> = (props) => {
const thsRef = useRef<Record<string, any>>({});
const columns = useMemo(() => props.columns ?? [], [props.columns]);
const [propsColumns, setPropsColumns] = useState<ColumnType<any>[]>([]);
const scrollX = useMemo(
() =>
propsColumns
.slice()
.reduce((pre, next) => (pre += Number(next?.width ?? 200)), 0),
[propsColumns]
);
const lastColumns = useMemo(() => {
const initialColumns: ColumnType<any>[] = [];
if (columns?.length === 0) {
return [];
}
const handleResize = (dataIndex: any) => (width: number) => {
if (!dataIndex) return;
setPropsColumns((cur) =>
cur.map((v) => ({
...v,
width: v.dataIndex === dataIndex ? width : v.width,
}))
);
};
columns.forEach((n: any) => {
if (propsColumns.find((v) => v.dataIndex === n.dataIndex)) {
n.width = propsColumns.find((v) => v.dataIndex === n.dataIndex)?.width;
}
if (!n.fixed && n.dataIndex && n.title) {
n.onHeaderCell = (wwcolumn: ColumnType<any>) => {
return {
width: wwcolumn.width,
thRef: thsRef,
dataIndex: JSON.stringify(n.dataIndex),
onResize: handleResize(n.dataIndex),
};
};
}
initialColumns.push({ ...n, ellipsis: true });
});
return initialColumns;
}, [columns, propsColumns]);
useEffect(() => {
setPropsColumns(columns)
}, [columns])
return (
<>
<Table
{...props}
components={{
header: {
cell: ResizeTitle,
},
...props.components,
}}
scroll={{ x: scrollX, y: props.scroll?.y }}
columns={lastColumns}
/>
</>
);
};
export default Index;
// resizeTitle.tsx
import { memo } from "react";
import Draggable from "react-draggable";
import styled from "styled-components";
import "react-resizable/css/styles.css";
const Handle = styled.div`
position: absolute !important;
right: 0 !important;
bottom: 0 !important;
z-index: 10 !important;
width: 4px !important;
height: 100% !important;
background: none !important;
cursor: col-resize !important;
&:hover {
background-color: #1890ff !important;
}
`;
const ResizeableTitle = memo((props: any) => {
const { onResize, width, thRef, dataIndex, ...restProps } = props;
const tmplTH = <th {...restProps} />;
if (!onResize) {
return tmplTH;
}
const _width = width || thRef.current[dataIndex]?.clientWidth;
return (
<th ref={(e) => (thRef.current[dataIndex] = e)}>
<div style={{ minWidth: 50 }} {...restProps}>
{restProps.children}
</div>
<Draggable
axis="x"
position={{ x: 0, y: 0 }}
onStop={(e, data) => {
const lastWidth = _width + data.x > 50 ? _width + data.x : 50;
onResize(lastWidth);
}}
>
<Handle />
</Draggable>
</th>
);
});
export default ResizeableTitle;
虚拟列表
import React, { FC, Key, useCallback, useMemo } from 'react';
import { TableProps } from "antd";
import { VList, scrollTo } from "virtuallist-antd";
import styled from 'styled-components';
import ProTable from "@/componets/ProTable";
interface ProScopeTableProps extends TableProps<any> {
pageSize?: number
current?: number
loadDataSize?: number
total?: number
checkIds?: Key[]
onLoadMore?: () => void
};
const ProScopeTable: FC<ProScopeTableProps> = (props) => {
// 已加载多少条
const loadSize = useMemo(() => props.dataSource?.map(item => item?.children)?.flat()?.length ?? 0, [props.dataSource])
const scrollY = useMemo(() => props?.scroll?.y ?? 500, [props?.scroll?.y])
const vc = useMemo(() => {
return VList({
height: scrollY,
resetTopWhenDataChange: false
})
}, [scrollY])
const handleScrollTop = useCallback(() => {
scrollTo({ row: 0 })
}, [])
const handleScrollBottom = useCallback(() => {
const row = props.dataSource?.map(item => item?.children)?.flat()?.length
scrollTo({ row })
}, [props.dataSource])
return (
<>
<TableStyle
height={scrollY}
{...props}
size={props.size || 'small'}
pagination={false}
scroll={{ y: scrollY }}
components={vc}
/>
</>
)
}
export default ProScopeTable;
const TableStyle = styled(ProTable)<{height?: any}>`
.virtuallist {
min-height: ${props => props.height ?? '500px'} !important;
tr {
height: auto !important;
}
}
`