123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- import { Table } from 'antd';
- import type { TableProps } from 'antd';
- import classNames from 'classnames';
- import ResizeObserver from 'rc-resize-observer';
- import React, { useEffect, useRef, useState } from 'react';
- import { VariableSizeGrid as Grid } from 'react-window';
- const VirtualTable = <RecordType extends object>(props: TableProps<RecordType>) => {
- const { columns, scroll } = props;
- const [tableWidth, setTableWidth] = useState(0);
- const widthColumnCount = columns!.filter(({ width }) => !width).length;
- const mergedColumns = columns!.map(column => {
- if (column.width) {
- return column;
- }
- return {
- ...column,
- width: Math.floor(tableWidth / widthColumnCount),
- };
- });
- const gridRef = useRef<any>();
- const [connectObject] = useState<any>(() => {
- const obj = {};
- Object.defineProperty(obj, 'scrollLeft', {
- get: () => {
- if (gridRef.current) {
- return gridRef.current?.state?.scrollLeft;
- }
- return null;
- },
- set: (scrollLeft: number) => {
- if (gridRef.current) {
- gridRef.current.scrollTo({ scrollLeft });
- }
- },
- });
- return obj;
- });
- const resetVirtualGrid = () => {
- gridRef.current?.resetAfterIndices({
- columnIndex: 0,
- shouldForceUpdate: true,
- });
- };
- useEffect(() => resetVirtualGrid, [tableWidth]);
- const renderVirtualList = (rawData: object[], { scrollbarSize, ref, onScroll }: any) => {
- ref.current = connectObject;
- const totalHeight = rawData.length * 54;
- return (
- <Grid
- ref={gridRef}
- className="virtual-grid"
- columnCount={mergedColumns.length}
- columnWidth={(index: number) => {
- const { width } = mergedColumns[index];
- return totalHeight > (scroll!.y! as any) && index === mergedColumns.length - 1
- ? (width as number) - scrollbarSize - 1
- : (width as number);
- }}
- height={scroll!.y as number}
- rowCount={rawData.length}
- rowHeight={() => 54}
- width={tableWidth}
- onScroll={({ scrollLeft }: { scrollLeft: number }) => {
- onScroll({ scrollLeft });
- }}
- >
- {({
- columnIndex,
- rowIndex,
- style,
- }: {
- columnIndex: number;
- rowIndex: number;
- style: React.CSSProperties;
- }) => (
- <div
- className={classNames('virtual-table-cell', {
- 'virtual-table-cell-last': columnIndex === mergedColumns.length - 1,
- })}
- style={style}
- >
- {(rawData[rowIndex] as any)[(mergedColumns as any)[columnIndex].dataIndex]}
- </div>
- )}
- </Grid>
- );
- };
- return (
- <ResizeObserver
- onResize={({ width }) => {
- setTableWidth(width);
- }}
- >
- <Table
- {...props}
- className="virtual-table"
- columns={mergedColumns}
- pagination={false}
- components={{
- body: renderVirtualList as any,
- }}
- />
- </ResizeObserver>
- );
- };
- export default React.memo(VirtualTable)
|