目录
- react中hook封装一个table组件
-
- 依赖
- CommonTable / index.tsx
- 使用组件
- 效果
react中hook封装一个table组件
依赖
cnpm i react-resizable --save
cnpm i ahooks
cnpm i --save-dev @types/react-resizable
CommonTable / index.tsx
import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { createUseStyles } from 'react-jss';
import { Resizable } from 'react-resizable';
import { ColumnType } from 'antd/lib/table';
import { Table, Button } from 'antd';
import type { ButtonProps, TableProps } from 'antd';
import { useSize } from 'ahooks';
export interface ICommonTableProps<RecordType> extends TableProps<RecordType> {
onCreate?: () => void;
onEdit?: () => void;
deleteBtn?: {
props?: ButtonProps;
onDelete?: () => void;
};
isDrag?: boolean;
}
const useCommonTableStyles = createUseStyles({
wrapper: {
background: '#fff',
marginTop: '12px',
padding: '12px 12px'
},
header: {
display: 'flex',
marginTop: '8px',
marginBottom: '20px'
},
tablActions: {
display: 'flex',
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center'
},
headerBtn: {
marginLeft: '16px'
},
resizableHandle : {
position: 'absolute',
right: '-5px',
bottom: 0,
zIndex: 1,
width: '10px',
height: '100%',
cursor: 'col-resize'
}
});
const ResizableTitle = (props: any ) => {
const { onResize, width, ...restProps } = props
const classes = useCommonTableStyles();
if (!width) { return (<th {...restProps} />) };
return (
<Resizable
width={parseInt(width)}
height={0}
handle={
<span className={classes.resizableHandle} onClick={e => { e.stopPropagation() }} />
}
onResize={onResize}
draggableOpts={{ enableUserSelectHack: false }}
>
<th {...restProps} style={{ ...restProps?.style, userSelect: 'none' }} />
</Resizable>
);
};
export const CommonTable = <RecordType extends Record<string, any> = any>(
props: ICommonTableProps<RecordType>
) => {
const { onCreate, onEdit, deleteBtn, isDrag = true } = props;
const classes = useCommonTableStyles();
const wrapperRef = useRef<HTMLDivElement>(null);
const bodyRef = useRef(document.body);
const size = useSize(bodyRef);
const [scroll, setScroll] = useState<TableProps<any>['scroll']>({ x: 'max-content' });
const [rescolumns, setResColumns] = useState<ColumnType<RecordType>[]>(props.columns || []);
const handleResize = (index: number): ((_: any, Resize: { size: { width: any } }) => void) => {
return (_: any, Resize: { size: { width: any; }; }) => {
const temp = [...rescolumns];
temp[index] = { ...temp[index], width: Resize.size.width };
setResColumns(temp);
};
};
const columnsMap: any[] = useMemo(() => {
return (
rescolumns?.map((column:any,index:any) => ({
...column,
onHeaderCell: (col: { width: any; }) => ({ width: col.width, onResize: handleResize(index) }),
title: column.title,
})) || []
);
}, [rescolumns]);
useEffect(() => {
if (wrapperRef.current) {
const { top } = wrapperRef.current?.getBoundingClientRect();
setScroll({
x: 'max-content',
y: innerHeight - top - 210
});
}
}, [wrapperRef, size]);
return (
<div className={classes.wrapper} ref={wrapperRef}>
<div className={classes.header}>
<div className={classes.tablActions}>
{onCreate && (
<Button className={classes.headerBtn} type='primary' onClick={onCreate}>
新增
</Button>
)}
{onEdit && (
<Button className={classes.headerBtn} type='default'>
编辑
</Button>
)}
{deleteBtn && (
<Button
{...deleteBtn.props}
className={classes.headerBtn}
type='default'
danger
onClick={deleteBtn.onDelete}
>
删除
</Button>
)}
</div>
</div>
<Table
scroll={scroll}
{...props}
components={isDrag ? { header: { cell: ResizableTitle } } : undefined}
columns={columnsMap}
/>
</div>
);
};
使用组件
import { createUseStyles } from 'react-jss';
import type { TableRowSelection } from 'antd/lib/table/interface';
import type { ColumnsType } from 'antd/lib/table';
import { useEffect, useMemo, useState, useRef } from 'react';
import { CommonTable } from '../components/CommonTable/index';
const useStyles = createUseStyles({
table: {
background: '#fff',
padding: '16px',
marginTop: '16px',
width: '100%',
},
textBtn: {
color: '#0068FF',
cursor: 'pointer',
userSelect: 'none',
},
});
const TablePage = () => {
const [tableData, setTableData] = useState<any>([]);
const [currentPage, setCurrentPage] = useState<number>(1);
const [currentSize, setCurrentSize] = useState<number>(20);
const classes = useStyles();
const [tableLoading, setTableLoading] = useState(false);
const [tableDataTotal, setTableDataTotal] = useState(0);
const [selectedRow, setSelectedRow] = useState([] as any);
useEffect(() => {
const resTable = [
{ id: 1, type: 1, status: '草稿' },
{ id: 2, type: 0, status: '已完成' },
{ id: 3, type: 1, status: '草稿' },
];
setTableData(resTable);
}, []);
const rowSelection: TableRowSelection<any> = {
onChange: (selectedRowKeys, selectedRows) => {
setSelectedRow(selectedRowKeys);
},
};
const handlePageChange = (page: number, size: number) => {
setCurrentPage(page);
setCurrentSize(size);
};
const tableColumns: ColumnsType<any> = useMemo(() => {
return [
{
title: '操作',
dataIndex: 'code',
fixed: 'left',
width: '100px',
render: (text, record) => (
<div
className={classes.textBtn}
onClick={() => {
console.log('onClick', text,"record",record);
}}
>
{record['status'] === '草稿' ? '编辑' : '查看'}
</div>
),
},
{
title: '序号',
dataIndex: 'id',
width: '60px',
render: (_, __, index) => index + 1 + (currentPage - 1) * currentSize,
},
{
title: '来源',
dataIndex: 'type',
render: (_, __, index) => (_ === 1 ? '系统' : '手工'),
},
];
}, [classes.textBtn, currentPage, currentSize]);
return (
<>
<CommonTable
rowKey={'id'}
className={classes.table}
columns={tableColumns}
scroll={{
x: 'max-content',
}}
pagination={{
showTotal: () => `共 ${tableDataTotal} 条记录`,
onChange: (page, size) => handlePageChange(page, size),
hideOnSinglePage: false,
showQuickJumper: true,
showSizeChanger: true,
current: currentPage,
pageSize: currentSize,
total: tableDataTotal,
}}
dataSource={tableData}
loading={tableLoading}
rowSelection={rowSelection}
/>
<CommonTable
rowKey={'id'}
isDrag={false}
className={classes.table}
columns={tableColumns}
scroll={{
x: 'max-content',
}}
pagination={{
showTotal: () => `共 ${tableDataTotal} 条记录`,
onChange: (page, size) => handlePageChange(page, size),
hideOnSinglePage: false,
showQuickJumper: true,
showSizeChanger: true,
current: currentPage,
pageSize: currentSize,
total: tableDataTotal,
}}
dataSource={tableData}
loading={tableLoading}
rowSelection={rowSelection}
/>
</>
);
};
export default TablePage;
效果