react中hook封装一个table组件

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; // 控制table是否展示 可拖拽的表头
}
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);
    };
  };

  // 把 columns 用 map 重组为支持可拖拽的cell
  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);
    // getList({ page, size, param: queryData }); // 获取table数据
  };
  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',
        // width: '130px', // 最后一个宽度不传
        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;

效果

在这里插入图片描述

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-02-07 19:44:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-07 19:44:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-07 19:44:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-07 19:44:01       18 阅读

热门阅读

  1. 【Office】或得单元格中以/分隔的后半部分

    2024-02-07 19:44:01       26 阅读
  2. 多头注意力和多尺度注意力的区别

    2024-02-07 19:44:01       34 阅读
  3. Python 套接字详解:与网络通信的温柔邂逅

    2024-02-07 19:44:01       31 阅读
  4. WPF绘制矢量图形并绑定到界面的方法

    2024-02-07 19:44:01       32 阅读
  5. jpeg压缩基本步骤

    2024-02-07 19:44:01       34 阅读
  6. 【工厂模式】

    2024-02-07 19:44:01       26 阅读
  7. C# 旋描仪或扫描仪

    2024-02-07 19:44:01       28 阅读
  8. C Primer Plus(第六版)15.9 编程练习 第7题

    2024-02-07 19:44:01       28 阅读
  9. Python_百度贴吧评论情感分析

    2024-02-07 19:44:01       35 阅读