react实现table可拖拽表头
安装依赖
yarn add react-resizable
yarn add react-jss
resizableTitle / index.tsx
import { createUseStyles } from 'react-jss';
import { Resizable } from 'react-resizable';
const useResizableTitleStyles = createUseStyles({
resizableHandle : {
position: 'absolute',
right: '-5px',
bottom: 0,
zIndex: 1,
width: '10px',
height: '100%',
cursor: 'col-resize'
}
});
export const ResizableTitle = ({ onResize, width, isNotResizable, ...restProps }) => {
const classes = useResizableTitleStyles();
const stopPropagation = (event) => event.stopPropagation();
console.log('isNotResizable',isNotResizable, width, 'restProps', restProps);
if (!width || isNotResizable) { return (<th {...restProps} />) };
return (
<Resizable
width={width}
height={0}
handle={
<span className={classes.resizableHandle} onClick={stopPropagation} />
}
onResize={onResize}
draggableOpts={{ enableUserSelectHack: false }}
>
<th {...restProps} style={{ ...restProps?.style, userSelect: 'none' }} />
</Resizable>
);
};
drapTable.tsx
import type { TableProps } from 'antd';
import { Table } from 'antd';
import { useState, useMemo, useEffect, useCallback } from 'react';
import type { ColumnType } from 'antd/lib/table';
import { ResizableTitle } from './resizableTitle/index';
import { createUseStyles } from 'react-jss';
interface TableStylesProps {
paddingVertical?: number;
paddingHorizontal?: number;
}
const useTableStyles = createUseStyles({
base_table_com: {
'& .ant-table-thead > tr > th, & .ant-table-tbody > tr > td, & .ant-table tfoot > tr > th, & .ant-table tfoot > tr > td':
{
padding: (cProps: TableStylesProps) =>
`${cProps.paddingVertical ?? 10}px ${
cProps.paddingHorizontal ?? 12
}px`,
},
},
});
export const DragTable = <RecordType extends Record<string, any> = any>(
props: ICommonTableProps<RecordType>,
) => {
const {
showTotalNum = true,
pagination,
hidePagination,
paddingVertical,
paddingHorizontal,
} = props;
const [tablePagination, setTablePagination] = useState<any>(pagination);
const classes = useTableStyles({ paddingVertical, paddingHorizontal });
const { columns } = props;
const [rescolumns, setResColumns] = useState<ColumnType<any>[]>(
columns.filter((column) => !column.hide) || [],
);
const handleResize = useCallback(
(index) => {
return (txt: any, Resize: any) => {
const temp = [...rescolumns];
temp[index] = { ...temp[index], width: Resize.size.width };
setResColumns(temp);
};
},
[rescolumns],
);
const columnsMap: any[] = useMemo(() => {
return (
rescolumns?.map((column: any, index) => {
return {
...column,
onHeaderCell: (col: any) => ({
width: col.width,
onResize: handleResize(index),
isNotResizable: col.isNotResizable
}),
};
}) || []
);
}, [rescolumns, handleResize]);
useEffect(() => {
const showTotal = {
showTotal: (total: number, range: number[]) => {
if (showTotalNum) {
return `共{${props.pagination ? props.pagination?.total : 0}}条结果`;
} else {
return '';
}
},
};
if (!hidePagination) {
setTablePagination(Object.assign({}, pagination ?? {}, showTotal));
} else {
setTablePagination(false);
}
}, [hidePagination, pagination, props.pagination, showTotalNum]);
return (
<Table
{...props}
columns={columnsMap}
pagination={tablePagination}
components={{ header: { cell: ResizableTitle } }}
className={classes.base_table_com}
/>
);
};
interface CommonColumn<T> extends ColumnType<T> {
hide?: boolean;
}
export interface ICommonTableProps<RecordType> extends TableProps<RecordType> {
showTotalNum?: boolean;
hidePagination?: boolean;
columns: CommonColumn<RecordType>[];
paddingVertical?: number;
paddingHorizontal?: number;
}
使用DragTable 组件
import { createUseStyles } from 'react-jss';
import { useEffect, useMemo, useState, useRef } from 'react';
import { DragTable } from './drapTable';
import { Space } from "antd"
const TablePage = () => {
const columns = [
{
title: '操作',
width: 60,
isNotResizable: true,
render: (_, record) => (
<Space size="middle">
<a>删除</a>
</Space>
),
},
{
title: '编码',
dataIndex: 'code',
width: 100,
},
{
title: '名称',
width: 100,
dataIndex: 'name',
},
{
title: '测试',
dataIndex: 'test',
width: 400,
},
{
title: '描述',
dataIndex: 'des',
width: 400,
},
];
const dataSource = [
{ id: 1, code: '001', name: '我是name1', test: '测试一下1', des: '描述一下' },
{ id: 2, code: '002', name: '我是name2', test: '测试一下2', des: '描述一下2' },
{ id: 3, code: '003', name: '我是name3', test: '测试一下3', des: '描述一下3' },
{ id: 4, code: '004', name: '我是name4', test: '测试一下4', des: '描述一下4' },
{ id: 5, code: '005', name: '我是name5', test: '测试一下5', des: '描述一下5' },
{ id: 6, code: '006', name: '我是name6', test: '测试一下6', des: '描述一下6' },
{ id: 7, code: '007', name: '我是name7', test: '测试一下7', des: '描述一下7' },
{ id: 8, code: '008', name: '我是name8', test: '测试一下8', des: '描述一下8' },
{ id: 9, code: '009', name: '我是name9', test: '测试一下9', des: '描述一下9' },
];
return (
<>
<DragTable
rowKey="id"
paddingVertical={8}
paddingHorizontal={10}
columns={columns}
dataSource={dataSource}
scroll={{ x: 'max-content', y : 250 }}
/>
</>
);
};
export default TablePage;
滚动条样式
::-webkit-scrollbar {
width: 6px;
height: 6px;
background-color: #f5f5f5;
}
::-webkit-scrollbar-thumb {
background-color: #999;
border-radius: 4px;
cursor: pointer;
}
::-webkit-scrollbar-track {
background-color: #f5f5f5;
}
效果
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fd9807beb1564138b3c1a7aa6e10da3c.png)