react中hook封装一个table组件 与 useColumns组件

目录

  • 1:react中hook封装一个table组件
    • 依赖
    • CommonTable / index.tsx
    • 使用组件
    • 效果
  • 2:useColumns组件
    • useColumns.tsx
    • 使用

1: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 } = propsconst classes = useCommonTableStyles();if (!width) { return (<th {...restProps} />) };return (<Resizablewidth={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 重组为支持可拖拽的cellconst 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'dangeronClick={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) => (<divclassName={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 (<><CommonTablerowKey={'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}/><CommonTablerowKey={'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;

效果

在这里插入图片描述

2:useColumns组件

useColumns.tsx

import React, { useMemo, useCallback } from 'react';interface Args {handleEdit: (r: any) => void;handleSeeDetail: (r: any) => void;
}export const useColumns = ({ handleEdit, handleSeeDetail }: Args) => {const handleEvent = useCallback((v: string, record: any, e) => {e.stopPropagation();if (v === '编辑') {handleEdit(record);} else {handleSeeDetail(record);}},[handleSeeDetail, handleEdit],);// 渲染查看 || 编辑const showPop = useCallback((record: any) => {if (record.status === '1') {return (<spanonClick={(e) => handleEvent('编辑', record, e)}className="check-btn">编辑</span>);} else {return (<spanonClick={(e) => handleEvent('查看', record, e)}className="check-btn">查看</span>);}},[handleEvent],);const columnsData: any = useMemo(() => {const columns = [{title: '操作',width: '100px',fixed: 'left',render: (_: any, record: any) => showPop(record),},{title: '序号',width: '60px',render: (_: any, record: any, index: number) => `${index + 1}`,},{title: '名称',dataIndex: 'name',width: '130px',},{title: '年龄',dataIndex: 'age',},];return columns;}, [showPop]);return columnsData;
};export default useColumns;

使用

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';
import useColumns from "./useColumns"const useStyles = createUseStyles({table: {background: '#fff',padding: '16px',marginTop: '16px',width: '100%',},textBtn: {color: '#0068FF',cursor: 'pointer',userSelect: 'none',},
});
const TablePage = () => {const testData = [{ name: '测试1',age: 10 },{ name: '测试1',age: 20 },{ name: '测试1',age: 30 },]const handleSeeDetail = (row:any) => {console.log('查看', row);}const handleEdit = (row:any) => {console.log('编辑', row);}return (<><CommonTablerowKey={'id'}className={classes.table}dataSource={testData}scroll={{x: 'max-content',}}columns={useColumns({ handleSeeDetail, handleEdit })}/></>);
};
export default TablePage;

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

KingSCADA实现按钮点击效果

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 在做SCADA项目的时候&#xff0c;按钮是不可缺少的功能&#xff0c;但软件自带的按钮太丑&#xff0c;已经无法满足现如今客户对界面美观度的要求。 这时候就需要UI小姐姐设计美观大气的SCADA界面&#xff0c;但UI设计…

CoreSight学习笔记

文章目录 1 Components1.1 ROM Table 2 使用场景2.1 Debug Monitor中断2.1.1 参考资料 2.2 Programming the cross halt2.2.1 编程实现2.2.2 参考资料 2.3 CTI中断2.3.1 编程实现2.3.1.1 准备工作2.3.1.2 触发中断2.3.1.3 中断响应 2.3.2 参考资料 1 Components 1.1 ROM Table…

STM32 7-8

目录 ADC AD单通道 AD多通道 DMA DMA转运数据 DMAAD多通道 ADC AD单通道 AD.c #include "stm32f10x.h" // Device header/*** brief 初始化AD所需要的所有设备* param 无* retval 无*/ void AD_Init(void) {RCC_APB2PeriphClockCmd(RCC_AP…

相机图像质量研究(12)常见问题总结:光学结构对成像的影响--炫光

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

YOLOv5独家改进:上采样算子 | 超轻量高效动态上采样DySample,效果秒杀CAFFE,助力小目标检测

💡💡💡本文独家改进:一种超轻量高效动态上采样DySample, 具有更少的参数、FLOPs,效果秒杀CAFFE和YOLOv5网络中的nn.Upsample 💡💡💡在多个数据集下验证能够涨点,尤其在小目标检测领域涨点显著。 收录 YOLOv5原创自研 https://blog.csdn.net/m0_63774211/cate…

从github上拉取项目到pycharm中

有两种方法&#xff0c;方法一较为简单&#xff0c;方法二用到了git bash&#xff0c;推荐方法一 目录 有两种方法&#xff0c;方法一较为简单&#xff0c;方法二用到了git bash&#xff0c;推荐方法一方法一&#xff1a;方法二&#xff1a; 方法一&#xff1a; 在github上复制…

深度学习(15)--PyTorch构建卷积神经网络

目录 一.PyTorch构建卷积神经网络(CNN)详细流程 二.graphviz torchviz使PyTorch网络可视化 2.1.可视化经典网络vgg16 2.2.可视化自己定义的网络 一.PyTorch构建卷积神经网络(CNN)详细流程 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;是一种深度学…

【MySQL基础】:深入探索DQL数据库查询语言的精髓(上)

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; MySQL从入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一. DQL1.1 基本语法1.2 基础查询1.3 条件查询1.3 聚合函数 &#x1f324;️ 全篇…

【51单片机】串口通信实验(包括波特率如何计算)

目录 串口通信实验通信的基本概念串行通信与并行通信异步通信与同步通信单工、 半双工与全双工通信通信速率 51单片机串口介绍串口介绍串口通信简介串口相关寄存器串口工作方式方式0方式1方式 2 和方式 3 串口的使用方法&#xff08;计算波特率&#xff09; 硬件设计软件设计1、…

Akamai 如何揪出微软 RPC 服务中的漏洞

近日&#xff0c;Akamai研究人员在微软Windows RPC服务中发现了两个重要漏洞&#xff1a;严重程度分值为4.3的CVE-2022-38034&#xff0c;以及分值为8.8的CVE-2022-38045。这些漏洞可以利用设计上的瑕疵&#xff0c;通过缓存机制绕过MS-RPC安全回调。我们已经确认&#xff0c;所…

clickhouse计算前后两点间经纬度距离

问题 计算如图所示前后两点经纬度的距离&#xff1f; 方法 1、用开窗函数将如图所示数据下移一行 selectlongitude lon1,latitude lat1,min(longitude) over(order by time1 asc rows between 1 PRECEDING and 1 PRECEDING) lon2,min(latitude) over(order by time1 asc row…

小游戏和GUI编程(5) | SVG图像格式简介

小游戏和GUI编程(5) | SVG图像格式简介 0. 问题 Q1: SVG 是什么的缩写&#xff1f;Q2: SVG 是一种图像格式吗&#xff1f;Q3: SVG 相对于其他图像格式的优点和缺点是什么&#xff1f;Q4: 哪些工具可以查看 SVG 图像&#xff1f;Q5: SVG 图像格式的规范是怎样的&#xff1f;Q6…

CPP项目:Boost搜索引擎

1.项目背景 对于Boost库来说&#xff0c;它是没有搜索功能的&#xff0c;所以我们可以实现一个Boost搜索引擎来实现一个简单的搜索功能&#xff0c;可以更快速的实现Boost库的查找&#xff0c;在这里&#xff0c;我们实现的是站内搜索&#xff0c;而不是全网搜索。 2.对于搜索…

11.0 Zookeeper watcher 事件机制原理剖析

zookeeper 的 watcher 机制&#xff0c;可以分为四个过程&#xff1a; 客户端注册 watcher。服务端处理 watcher。服务端触发 watcher 事件。客户端回调 watcher。 其中客户端注册 watcher 有三种方式&#xff0c;调用客户端 API 可以分别通过 getData、exists、getChildren …

ELAdmin 前端启动

开发工具 官方指导的是使用WebStorm&#xff0c;但是本人后端开发一枚&#xff0c;最终还是继续使用了 idea&#xff0c;主打一个能用就行。 idea正式版激活方式&#xff1a; 访问这个查找可用链接&#xff1a;https://3.jetbra.in/进入任意一个能用的里面&#xff0c;顶部提…

kafka教程

Kafka 中&#xff0c;Producer采用push模型&#xff0c;而Consumer采用pull模型。 Topic Topic&#xff08;主题&#xff09;是消息的逻辑分类或通道。它是Kafka中用于组织和存储消息的基本单元。一个Topic可以被看作是一个消息发布的地方&#xff0c;生产者将消息发布到一个…

Axios设置token到请求头的三种方式

1、为什么要携带token? 用户登录时&#xff0c;后端会返回一个token&#xff0c;并且保存到浏览器的localstorage中&#xff0c;可以根据localstorage中的token判断用户是否登录&#xff0c;登录后才有权限访问相关的页面&#xff0c;所以当发送请求时&#xff0c;都要携带to…

ubuntu彻底卸载cuda 重新安装cuda

sudo apt-get --purge remove "*cublas*" "*cufft*" "*curand*" \"*cusolver*" "*cusparse*" "*npp*" "*nvjpeg*" "cuda*" "nsight*" cuda10以上 cd /usr/local/cuda-xx.x/bin/ s…

fast.ai 机器学习笔记(四)

机器学习 1&#xff1a;第 11 课 原文&#xff1a;medium.com/hiromi_suenaga/machine-learning-1-lesson-11-7564c3c18bbb 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;这些笔记将继续…

idea自带的HttpClient使用

1. 全局变量配置 {"local":{"baseUrl": "http://localhost:9001/"},"test": {"baseUrl": "http://localhost:9002/"} }2. 登录并将结果设置到全局变量 PostMapping("/login")public JSONObject login(H…