|
@@ -7,6 +7,25 @@ import classNames from "classnames";
|
|
|
import ResizeObserver from "rc-resize-observer";
|
|
|
import type { ColumnsType } from "antd/es/table";
|
|
|
import { VariableSizeGrid as Grid } from "react-window";
|
|
|
+import { Resizable } from "react-resizable";
|
|
|
+
|
|
|
+
|
|
|
+const ResizableHeader = (props: { [x: string]: any; onResize: any; width: any }) => {
|
|
|
+ const { onResize, width, ...restProps } = props;
|
|
|
+ if (!width) {
|
|
|
+ return <th {...restProps} />
|
|
|
+ }
|
|
|
+ return <Resizable width={width} height={0} onResize={onResize} draggableOpts={{ enableUserSelectHack: false }}>
|
|
|
+ <th {...restProps} />
|
|
|
+ </Resizable>
|
|
|
+}
|
|
|
+
|
|
|
+const getColumns = <RecordType extends object>(columns: ColumnsType<RecordType> | undefined) => {
|
|
|
+ return columns!.map((column) => {
|
|
|
+ if (column.width) return column;
|
|
|
+ return { ...column, width: 100 };
|
|
|
+ })
|
|
|
+}
|
|
|
|
|
|
interface Props<RecordType extends object> extends TableProps<RecordType> {
|
|
|
rowHeight: number
|
|
@@ -17,24 +36,51 @@ interface Props<RecordType extends object> extends TableProps<RecordType> {
|
|
|
defaultPageSize?: number
|
|
|
pageChange?: (page: number, pageSize?: number) => void,
|
|
|
sizeChange?: (current: number, size?: number) => void,
|
|
|
+ isShowTotal?: boolean
|
|
|
+ handelResize?: (columns: any) => void//当表头被拖动改变宽度时回调设置对应的本地保存
|
|
|
}
|
|
|
|
|
|
const VTable = <RecordType extends object>(props: Props<RecordType>) => {
|
|
|
|
|
|
- const { columns, scroll, className, rowHeight, loading = false, total = 0, current, pageSize, defaultPageSize, pageChange, sizeChange } = props;
|
|
|
+ const {
|
|
|
+ columns,
|
|
|
+ scroll,
|
|
|
+ className,
|
|
|
+ rowHeight,
|
|
|
+ loading = false,
|
|
|
+ total = 0,
|
|
|
+ current,
|
|
|
+ pageSize,
|
|
|
+ defaultPageSize,
|
|
|
+ pageChange,
|
|
|
+ sizeChange,
|
|
|
+ isShowTotal = true,
|
|
|
+ handelResize
|
|
|
+ } = props;
|
|
|
const [tableWidth, setTableWidth] = useState(0);
|
|
|
+ let bodyWidth = document.body.clientWidth < 415
|
|
|
+ const [mergedColumns, setMergedColumns] = useState<ColumnsType<RecordType>>(getColumns(columns))
|
|
|
+
|
|
|
+ useEffect(() => setMergedColumns(() => getColumns(columns)), [columns])
|
|
|
|
|
|
- // const widthColumnCount = columns!.filter(({ width }) => !width).length;
|
|
|
- const mergedColumns = columns!.map((column) => {
|
|
|
- if (column.width) {
|
|
|
- return column;
|
|
|
+ const handleResize = (index: any) => (e: any, { size }: any) => {
|
|
|
+ const nextColumns = [...mergedColumns]
|
|
|
+ nextColumns[index] = {
|
|
|
+ ...nextColumns[index],
|
|
|
+ width: size.width
|
|
|
}
|
|
|
- return {
|
|
|
- ...column,
|
|
|
- // width: Math.floor(tableWidth / widthColumnCount)
|
|
|
- width: 100
|
|
|
- };
|
|
|
- });
|
|
|
+ setMergedColumns(nextColumns)
|
|
|
+ handelResize?.(nextColumns)
|
|
|
+ }
|
|
|
+ const columnsRef = useRef<any[]>([])
|
|
|
+ columnsRef.current = (mergedColumns || []).map((col: any, index: any) => ({
|
|
|
+ ...col,
|
|
|
+ onHeaderCell: (column: any) => ({
|
|
|
+ width: column.width,
|
|
|
+ onResize: handleResize(index)
|
|
|
+ })
|
|
|
+ }))
|
|
|
+ console.log('---->', columnsRef.current)
|
|
|
|
|
|
const gridRef = useRef<any>();
|
|
|
const [connectObject] = useState<any>(() => {
|
|
@@ -65,25 +111,21 @@ const VTable = <RecordType extends object>(props: Props<RecordType>) => {
|
|
|
|
|
|
useEffect(() => resetVirtualGrid, [tableWidth]);
|
|
|
|
|
|
- const renderVirtualList = (
|
|
|
- rawData: object[],
|
|
|
- { scrollbarSize, ref, onScroll }: any
|
|
|
- ) => {
|
|
|
+ const renderVirtualList = (rawData: object[], { scrollbarSize, ref, onScroll }: any) => {
|
|
|
ref.current = connectObject;
|
|
|
- const totalHeight = rawData.length * 54;
|
|
|
-
|
|
|
+ const totalHeight = rawData.length * rowHeight + 6;
|
|
|
return (
|
|
|
<Grid
|
|
|
ref={gridRef}
|
|
|
className="virtual-grid"
|
|
|
- columnCount={mergedColumns.length}
|
|
|
+ columnCount={columnsRef.current.length}
|
|
|
columnWidth={(index: number) => {
|
|
|
- const { width } = mergedColumns[index];
|
|
|
- return totalHeight > (scroll!.y! as any) && index === mergedColumns.length - 1
|
|
|
+ const { width } = columnsRef.current[index];
|
|
|
+ return totalHeight > (scroll!.y! as any) && index === columnsRef.current.length - 1
|
|
|
? (width as number) - scrollbarSize - 1
|
|
|
: (width as number);
|
|
|
}}
|
|
|
- height={scroll!.y as number}
|
|
|
+ height={scroll!.y as number > totalHeight ? totalHeight : scroll!.y as number}
|
|
|
rowCount={rawData.length}
|
|
|
rowHeight={() => rowHeight}
|
|
|
width={tableWidth}
|
|
@@ -92,7 +134,10 @@ const VTable = <RecordType extends object>(props: Props<RecordType>) => {
|
|
|
}}
|
|
|
>
|
|
|
{({ columnIndex, rowIndex, style }: { columnIndex: number; rowIndex: number; style: React.CSSProperties; }) => {
|
|
|
- const { render, dataIndex, align } = (mergedColumns as any)[columnIndex];
|
|
|
+ const { render, dataIndex, align } = (columnsRef.current as any)[columnIndex];
|
|
|
+ if ((columnsRef.current as any)[columnIndex].title === 'C') {
|
|
|
+ console.log('style--->', style)
|
|
|
+ }
|
|
|
const myStyle = {
|
|
|
justifyContent:
|
|
|
align === "left"
|
|
@@ -105,7 +150,7 @@ const VTable = <RecordType extends object>(props: Props<RecordType>) => {
|
|
|
return (
|
|
|
<div
|
|
|
className={classNames("virtual-table-cell", {
|
|
|
- "virtual-table-cell-last": columnIndex === mergedColumns.length - 1
|
|
|
+ "virtual-table-cell-last": columnIndex === columnsRef.current.length - 1
|
|
|
})}
|
|
|
style={myStyle}
|
|
|
>
|
|
@@ -123,39 +168,39 @@ const VTable = <RecordType extends object>(props: Props<RecordType>) => {
|
|
|
};
|
|
|
|
|
|
return <Spin style={{ width: '100%' }} spinning={loading}>
|
|
|
- <div>
|
|
|
- <ResizeObserver
|
|
|
- onResize={({ width }) => {
|
|
|
- setTableWidth(width);
|
|
|
+ <ResizeObserver
|
|
|
+ onResize={({ width }) => {
|
|
|
+ setTableWidth(width);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Table
|
|
|
+ {...props}
|
|
|
+ bordered
|
|
|
+ className={`virtual-table all_table ${className ? className : ''}`}
|
|
|
+ columns={columnsRef.current}
|
|
|
+ pagination={{
|
|
|
+ defaultCurrent: 1,
|
|
|
+ total: total || 0,
|
|
|
+ current: current || 1,
|
|
|
+ pageSize: pageSize || 20,
|
|
|
+ defaultPageSize: defaultPageSize || 20,
|
|
|
+ pageSizeOptions: ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100'],
|
|
|
+ size: "small",
|
|
|
+ showTotal: (total) => isShowTotal ? <Tag color="cyan">总共{total}数据</Tag> : null,
|
|
|
+ showSizeChanger: true,
|
|
|
+ onChange: pageChange,
|
|
|
+ onShowSizeChange: sizeChange,
|
|
|
+ showLessItems: true,
|
|
|
+ simple: bodyWidth ? true : false,//开启简单分页
|
|
|
}}
|
|
|
- >
|
|
|
- <Table
|
|
|
- {...props}
|
|
|
- bordered
|
|
|
- className={`virtual-table all_table ${className ? className : ''}`}
|
|
|
- columns={mergedColumns}
|
|
|
- pagination={false}
|
|
|
- components={{
|
|
|
- body: renderVirtualList as any
|
|
|
- }}
|
|
|
- />
|
|
|
- </ResizeObserver>
|
|
|
- <div style={{ textAlign: 'end', padding: '16px 0', background: '#FFF' }}>
|
|
|
- <Pagination
|
|
|
- defaultCurrent={1}
|
|
|
- total={total || 0}
|
|
|
- current={current || 1}
|
|
|
- pageSize={pageSize || 20}
|
|
|
- defaultPageSize={defaultPageSize || 20}
|
|
|
- pageSizeOptions={['10', '20', '30', '40', '50', '60', '70', '80', '90', '100']}
|
|
|
- size="small"
|
|
|
- showTotal={(total) => <Tag color="cyan">总共{total}数据</Tag>}
|
|
|
- showSizeChanger={true}
|
|
|
- onChange={pageChange}
|
|
|
- onShowSizeChange={sizeChange}
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ components={{
|
|
|
+ header: {
|
|
|
+ cell: ResizableHeader
|
|
|
+ },
|
|
|
+ body: renderVirtualList as any
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </ResizeObserver>
|
|
|
</Spin>
|
|
|
};
|
|
|
|
|
@@ -217,7 +262,7 @@ const columns: ColumnsType<any> = [
|
|
|
|
|
|
const data = Array.from({ length: 100 }, (_, key) => ({
|
|
|
key,
|
|
|
- dd: "啊大大撒旦啊实打实大苏打阿斯顿撒打算阿三打撒"
|
|
|
+ dd: "啊大大撒1111"
|
|
|
}));
|
|
|
|
|
|
|