react中hook封装一个table组件

news2024/9/24 16:26:49

目录

  • 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; // 控制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;

效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1440180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】数据结构

本文是基于中国MOOC平台上&#xff0c;华中科技大学的《数据结构》课程和浙江大学的《数据结构》课程所作的一篇课程笔记&#xff0c;便于后期讲行系统性查阅和复习。 从个人角度出发&#xff0c;两个课程的讲解都有点不太易懂&#xff0c;好在多处可以互补&#xff0c;搭配进…

Backtrader 文档学习- Plotting -Plotting on the same axis

Backtrader 文档学习- Plotting -Plotting on the same axis 1.概述 在同一轴上绘图&#xff0c;绘图是在同一空间上绘制原始数据和稍微(随机)修改的数据&#xff0c;但不是在同一轴上。 核心代码&#xff0c;data数据正负50点。 # The filter which changes the close pri…

markdown加载自定义字体

写讲义&#xff0c;如果没有个像样 的字体多少有点难受。 最终的结果是劝退。 一、需要特定的markdown编辑器&#xff0c;我用的vscode 如果使用joplin、gitee的md文件是无法加载、渲染的。 二、 使用vscode想要渲染的话&#xff0c;似乎只能渲染一部分字体文件。下面不多…

【PyQt】09-控件提示信息、Lable标签

文章目录 前言一、控件提示信息1.1 代码1.2 解释 < b >在HTML标签中的作用1.3 添加按键后的代码运行结果 二、QLabel控件介绍2.1 内容2.2 常用的事件2.3 代码结果展示 总结 前言 1、控件提示信息 2、QLabel控件介绍 一、控件提示信息 关键点在于 效果如图所示&#x…

vFavorites

快速访问资产和文件夹的快捷方式 将您最常用的项目放入vFavorites中&#xff0c;以便立即访问 vFavorites中的项目与项目选项卡中的常规项目类似&#xff1a; - 单击文件夹以打开它 - 单击资产以选择它 - 双击脚本以进行编辑 - 拖放材料或预制件以将其添加到场景中 下载&#…

Qt网络编程-TCP与UDP

网络基础 TCP与UDP基础 关于TCP与UDP的基础这里就不过多介绍了&#xff0c;具体可以查看对应百度百科介绍&#xff1a; TCP&#xff08;传输控制协议&#xff09;_百度百科 (baidu.com) UDP_百度百科 (baidu.com) 需要知道这两者的区别&#xff1a; 可靠性&#xff1a; TC…

部署一个在线OCR工具

效果 安装 1.拉取镜像 # 从 dockerhub pull docker pull mmmz/trwebocr:latest 2.运行容器 # 运行镜像 docker run -itd --rm -p 10058:8089 --name trwebocr mmmz/trwebocr:latest 使用 打开浏览器输入 http://192.168.168.110:10058/ 愉快滴使用吧

五官行为检测(表情基)解决方案提供商

随着人工智能技术的日益成熟&#xff0c;情感识别与行为分析在企业界的应用逐渐广泛。美摄科技作为业内领先的五官行为检测&#xff08;表情基&#xff09;解决方案提供商&#xff0c;致力于为企业提供高效、精准的情感识别与行为分析服务。 美摄科技的五官行为检测&#xff0…

【网页设计期末】茶文化网站

本文资源&#xff1a;https://download.csdn.net/download/weixin_47040861/88818886 1.题目要求 设计要求&#xff1a; &#xff08;1&#xff09;网站页面数量不少于4个&#xff0c;文件命名规范&#xff0c;网站结构要求层次清楚&#xff0c;目录结构清晰&#xff0c;代码…

阿里云服务器多少钱?2024年阿里云服务器租用费用表大全

2024年阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

LabVIEW动平衡测试与振动分析系统

LabVIEW动平衡测试与振动分析系统 介绍了利用LabVIEW软件和虚拟仪器技术开发一个动平衡测试与振动分析系统。该系统旨在提高旋转机械设备的测试精度和可靠性&#xff0c;通过精确测量和分析设备的振动数据&#xff0c;以识别和校正不平衡问题&#xff0c;从而保证机械设备的高…

【状态管理一】概览:状态使用、状态分类、状态具体使用

文章目录 一. 状态使用概览二. 状态的数据类型1. 算子层面2. 接口层面2.1. UML与所有状态类型介绍2.2. 内部状态&#xff1a;InternalKvState 将知识与实际的应用场景、设计背景关联起来&#xff0c;这是学以致用、刨根问底知识的一种直接方式。 本文介绍 状态数据管理&#x…

闭区间上连续函数的性质【高数笔记】

1. 分几个性质 2. 每个性质的注意事项是什么 3. 每个性质适用什么类型的题型 4. 注意最值定理和正弦函数的不同 5. 做题步骤是什么

每日一题!如约而至!(图片整理,寻找数组的中心下标)

今天是腊月二十九&#xff0c;挂灯笼喽&#xff01; 图片整理_牛客题霸_牛客网 (nowcoder.com) #include <stdio.h> #include <string.h>int main() {char str[1001] {\0};while (scanf("%s", str) ! EOF) {//输入的是字符串int len strlen(str);for(…

C#,佩尔数(Pell Number)的算法与源代码

1 佩尔数&#xff08;Pell Number&#xff09; 佩尔数&#xff08;Pell Number&#xff09;是一个自古以来就知道的整数数列&#xff0c;由递推关系定义&#xff0c;与斐波那契数类似。佩尔数呈指数增长&#xff0c;增长速率与白银比的幂成正比。它出现在2的算术平方根的近似值…

UDP 用户数据报协议

目录 1 UDP 1.1 UDP 的主要特点 1.1.1 UDP 是面向报文的 1.1.2 UDP 通信和端口号的关系 1.2 UDP 的首部格式 1.2.1 UDP 基于端口的分用 1.3 UDP抓包 1 UDP UDP 只在 IP 的数据报服务之上增加了一些功能&#xff1a; 1.复用和分用 2.差错检测 1.1 UDP 的主要特点 1.无连…

VBA中类的解读及应用第九讲:用WithEvents关键字声明实例化对象类变量

《VBA中类的解读及应用》教程【10165646】是我推出的第五套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。 类&#xff0c;是非常抽象的&#xff0c;更具研究的价值。随着我们学习、应用VBA的深入&#xff0…

MVC框架学习

大一的时候写过一个mvc框架的跑酷游戏&#xff0c;但是那时候基础不扎实&#xff0c;没学明白也没听懂。现在深入的学习一下 以下内容参考&#xff1a;MVC 模式 | 菜鸟教程 (runoob.com) MVC 模式 MVC 模式代表 Model-View-Controller&#xff08;模型-视图-控制器&#xff…

LangChain 最近发布的一个重要功能:LangGraph

LangGraph 是 LangChain 最近发布的一个重要功能&#xff0c;LangChain 进入多代理框架领域。通过建立在LangChain 之上&#xff0c;LangGraph 使开发人员可以轻松创建强大的代理运行时。 LangChain 使用其表达语言&#xff08;LCEL&#xff09;为开发人员构建定制链提供技术支…

Django学习记录02

1.请求与响应 1.1get与post的区别 get 一般是从url输入地址&#xff0c;会调用get请求 post 一般是内部数据传输# get请求 def something(request):# req是一个对象&#xff0c;封装了用户发送过来的所有请求相关数据# 1.获取请求方式 http://localhost:8000/something# pri…