react + ts + material-ui V5版本的table封装

以下是一份 material-ui V5版本的table封装


import React, { forwardRef, useImperativeHandle, useEffect, useState } from 'react';
import {Table,TableBody,TableSortLabel,TableCell,TableContainer,TableHead,TableRow,Typography,Paper,Checkbox,CircularProgress,Box,TablePagination,Grid,Button
} from '@mui/material';
import { useDispatch } from 'store';
import { useIntl } from 'react-intl';
import { openSnackbar } from 'store/slices/snackbar';
// import { cloneDeep } from 'lodash';interface IColumn {slot?: string;title?: string;prop: string;fixed?: string;minWidth?: number;sorting?: boolean; // 是否可以排序titleRender?: (row: any, injectionData?: any) => React.ReactNode;render?: (row: any, injectionData?: any) => React.ReactNode;isRowSelectable?: (row: any) => boolean; // 新增属性,用于判断某行是否可以被勾选align?: 'left' | 'center' | 'right'; // 新增属性,用于指定对齐方式
}
// interface IRequiredParameters {
//     [key: string]: any;
// }interface ItableConfig {columns: IColumn[];Api: any; //请求接口方法fetchConfig?: {};onSort?: (column: string, order: 'asc' | 'desc') => void;showSelect?: boolean; // 控制是否显示选择框initParams?: {};requestParams?: {};pagination?: {fixedColumns?: string[];sorting?: boolean;pageSize: number;pageSizeOptions?: number[];};isDisableFirstRequest?: boolean; //是否禁用第一次进入时就请求接口  为true时,需要手动调用request方法rowKey?: string;isCacheCheckOptions?: boolean; // 新增属性,控制是否缓存勾选项dataRootArrKey?: string;paginationKey?: {pageSizeKeyName: string;totalCountKeyName: string;pageIndexKeyName: string;};injectionData?: any; //从外部注入的数据  给内部通讯dataListKey?: string; // data下面的第二级别list key的名称maxHeight?: number | string;onSelectChange?: (selected: any[]) => void; // 新增属性,当选择变化时调用 selectedIds: string[],showTablePagination?: boolean; //是否展示分页组件render?: (row: any) => React.ReactNode;getCurrentStatus?(status: boolean): any; //获取当前是否是loading状态  来同步search的按钮状态requiredParametersCallBack?: (params: any) => boolean; //搜索必要参数条件onChangeList?: (data: any[], obj: any) => void; // 获取列表数据回调onGetListAfter?: (ls?: any[]) => void; // 获取列表成功后调用一下
}// type Order = 'asc' | 'desc';
export interface TableMethods {getTableList: (option?: any) => void; // 你希望父组件能调用的方法resetTableList: (option?: any) => void; // 你希望父组件能调用的方法clearSelection: () => void; // 新增的方法getCheckedRows: () => void;
}
const EnhancedTable = forwardRef<TableMethods, ItableConfig>(({columns,Api,showTablePagination = true,paginationKey = {pageSizeKeyName: 'pageSize',totalCountKeyName: 'total',pageIndexKeyName: 'page'},onSort,initParams = {},onSelectChange,showSelect = false,dataRootArrKey,rowKey = 'id',pagination = {pageSize: 10},maxHeight = 610,requestParams = [],dataListKey = 'list',isCacheCheckOptions = false,isDisableFirstRequest = false,getCurrentStatus,requiredParametersCallBack = null,onChangeList,onGetListAfter,injectionData},ref) => {// 使用 useImperativeHandle 来暴露方法给父组件useImperativeHandle(ref, () => ({getTableList(option?: any) {option ? getList(option) : getList();},resetTableList(option?: any) {// ... 实现你希望父组件能调用的方法if (page === 0 && rowsPerPage === pagination.pageSize) {option ? getList(option) : getList();} else {setRowsPerPage(pagination.pageSize);setPage(0);}},getCheckedRows() {return selected;},clearSelection // 暴露新的方法}));const [isRestPageIndex, setIsRestPageIndex] = useState(true);const getStickyStyle = (column: IColumn, index: number): React.CSSProperties => {if (column.fixed) {return {position: 'sticky',borderLeft: column.fixed === 'right' ? '1px solid rgba(224, 224, 224, 1)' : undefined,boxShadow: column.fixed === 'right' ? '-2px 0px 3px rgba(0, 0, 0, 0.2)' : undefined,right: column.fixed === 'right' ? 0 : undefined,left: column.fixed === 'left' ? 0 : undefined,backgroundColor: '#fff',zIndex: 2};}return {};};const dispatch = useDispatch();const intl = useIntl();const [data, setData] = useState<any[]>([]);const [rowsPerPage, setRowsPerPage] = useState(pagination.pageSize || 10);const [loading, setLoading] = useState(false);const [order, setOrder] = useState<'asc' | 'desc'>('asc');const [orderBy, setOrderBy] = useState<string | null>(null);const [totalCount, setTotalCount] = useState(0);const [selected, setSelected] = useState<any[]>([]);const [page, setPage] = useState(0);const defaultErrorMessage = '出了点问题请稍后再试';// const [lastRequestParams, setLastRequestParams] = useState<any>({});// 新增的方法来清除所有勾选项const clearSelection = () => {setSelected([]);if (onSelectChange) {onSelectChange([]);}};// isDisableFirstRequestconst [flagFirst, setFlagFirst] = useState(false);useEffect(() => {if (isDisableFirstRequest) {if (flagFirst) {getList();} else {setFlagFirst(true);}} else {getList();}}, [page, rowsPerPage]);useEffect(() => {getCurrentStatus && getCurrentStatus(loading);}, [loading]);const [isCacheCheckFlag, setIsCacheCheckFlag] = useState(false);const getList = async (option = {}) => {if (loading) return;var ppppageIndex = page + 1;if (isRestPageIndex) {setPage(0);ppppageIndex = 1;}try {var params: any = {[paginationKey.pageIndexKeyName]: ppppageIndex, //TablePagination ui是从0开始的[paginationKey.pageSizeKeyName]: rowsPerPage,...initParams,...requestParams,...option};if (!!requiredParametersCallBack) {var fl: boolean = requiredParametersCallBack(params); //返回true才截断if (fl) {return false;}}setLoading(true);// 如果请求参数变化,并且不是因为翻页或修改每页条数(即是一次新的搜索),则清除勾选项if (showSelect) {if (isCacheCheckOptions) {if (isCacheCheckFlag// (lastRequestParams[paginationKey.pageIndexKeyName] !== params[paginationKey.pageIndexKeyName] ||//     lastRequestParams[paginationKey.pageSizeKeyName] !== params[paginationKey.pageSizeKeyName])) {setIsCacheCheckFlag(false);}} else {clearSelection();}}const res = await Api(params, dispatch, intl);// // 更新最后一次请求参数// setLastRequestParams(cloneDeep(params));setLoading(false);setIsRestPageIndex(true);if (res.code === 0) {const datas: {[dataListKey: string]: any;} = res.data;const ls = datas[dataListKey];if (ls && Array.isArray(ls)) {setData(ls);const ss = paginationKey.totalCountKeyName as string;var num = datas[ss] as number;setTotalCount(num); //总页码onChangeList?.(ls, res);} else {setData([]);setTotalCount(0);}onGetListAfter && onGetListAfter(ls);} else {setLoading(false);setData([]);setTotalCount(0);onChangeList?.([], res);dispatch(openSnackbar({open: true,message: res.msg || defaultErrorMessage,variant: 'alert',alert: {color: 'error'},close: false,anchorOrigin: {vertical: 'top',horizontal: 'center'}}));}} catch (error) {setLoading(false);setIsRestPageIndex(true);console.log('error error error', error);}};const handleSortRequest = (column: string) => {const isAsc = orderBy === column && order === 'asc';setOrder(isAsc ? 'desc' : 'asc');setOrderBy(column);onSort?.(column, isAsc ? 'desc' : 'asc');};const handleClick = (event: React.MouseEvent<unknown>, row: any) => {const isSelectable = columns.every((column) => (column.isRowSelectable ? column.isRowSelectable(row) : true));if (!isSelectable) {// 如果行不可选,直接返回不执行任何操作return;}const selectedIndex = selected.findIndex((r) => r[rowKey] === row[rowKey]);let newSelected: any[] = [];if (selectedIndex === -1) {newSelected = newSelected.concat(selected, row);} else if (selectedIndex === 0) {newSelected = newSelected.concat(selected.slice(1));} else if (selectedIndex === selected.length - 1) {newSelected = newSelected.concat(selected.slice(0, -1));} else if (selectedIndex > 0) {newSelected = newSelected.concat(selected.slice(0, selectedIndex), selected.slice(selectedIndex + 1));}setSelected(newSelected);onSelectChange?.(newSelected);};const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>) => {if (event.target.checked) {// 仅选择那些满足 isRowSelectable 条件的行const newSelecteds = data.filter((row) =>columns.every((column) => (column.isRowSelectable ? column.isRowSelectable(row) : true)));setSelected(newSelecteds);onSelectChange?.(newSelecteds);} else {setSelected([]);onSelectChange?.([]);}};const handleChangePage = (_event: unknown, newPage: number) => {setIsCacheCheckFlag(true);setPage(newPage);setIsRestPageIndex(false);};const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {setIsCacheCheckFlag(true);setRowsPerPage(parseInt(event.target.value, 10));};return (<Box>{showSelect && (<Box sx={{ minHeight: '38px' }}><Grid container><Grid item><Typographysx={{fontSize: '16px',paddingTop: '5px'}}variant="h6">{'已勾选'}:<Buttonsx={{cursor: 'auto',padding: '0',minWidth: '20px'}}>{selected.length}</Button>{'项'}</Typography></Grid>{selected.length > 0 && (<Griditemsx={{marginLeft: '10px'}}><Button onClick={clearSelection}> {'取消选择'}</Button></Grid>)}</Grid></Box>)}<Paper sx={{ width: '100%', overflow: 'hidden' }}><TableContainer component={Paper} sx={{ maxHeight: maxHeight, overflow: 'auto' }}><TablestickyHeaderaria-label="sticky table"sx={{minWidth: 750,tableLayout: 'auto','& .MuiTableCell-root': {borderBottom: '1px solid rgba(224, 224, 224, 1)' // 底部边框}}}><TableHead><TableRow>{showSelect && (<TableCell padding="checkbox"><Checkboxindeterminate={selected.length > 0 && selected.length < totalCount}checked={totalCount > 0 && selected.length === totalCount}onChange={handleSelectAllClick}inputProps={{ 'aria-label': 'select all desserts' }}/></TableCell>)}{columns.map((column) => (<TableCellalign={column.align || 'left'} // 使用 align 属性,如果未指定,默认为左对齐key={column.prop ? column.prop : Math.floor(Math.random() * 10000) + ''}style={{minWidth: column?.minWidth,position: column.fixed ? 'sticky' : undefined,top: 0, // 确保固定列头在顶部right: column.fixed === 'right' ? 0 : undefined,backgroundColor: '#f8fafc', // 确保固定列的背景色不透明zIndex: column.fixed ? 110 : 1, // 确保固定列在滚动时覆盖其他列,1100 是 MUI 中的 AppBar zIndexborderLeft: column.fixed === 'right' ? '1px solid rgba(224, 224, 224, 1)' : undefined,boxShadow: column.fixed === 'right' ? '-2px 0px 3px rgba(0, 0, 0, 0.2)' : undefined}}sortDirection={orderBy === column.prop ? order : false}>{column.titleRender ? (column.titleRender(column, injectionData)) : column.sorting ? (<TableSortLabelactive={orderBy === column.prop}direction={orderBy === column.prop ? order : 'asc'}onClick={() => handleSortRequest(column.prop)}>{column.title}</TableSortLabel>) : (column.title)}</TableCell>))}{columns.map((column) =>column.slot === 'right' ? (<TableCell key={column.prop} style={{ minWidth: column.minWidth }}>{column.title}</TableCell>) : null)}</TableRow></TableHead><TableBody>{loading ? (<TableRow><TableCell colSpan={columns.length + (showSelect ? 1 : 0)} style={{ textAlign: 'center' }}><CircularProgress /></TableCell></TableRow>) : data.length > 0 ? (data.map((row, index) => {const isItemSelected = selected.some((r) => r[rowKey] === row[rowKey]);const labelId = `enhanced-table-checkbox-${index}`;// 使用 column 中的 isRowSelectable 函数来判断行是否可选,如果没有提供,则默认为可选const isSelectable = columns.every((column) =>column.isRowSelectable ? column.isRowSelectable(row) : true);return (<TableRowhoveronClick={showSelect? (event) => {// 检查该行是否可选const isSelectable = columns.every((column) =>column.isRowSelectable ? column.isRowSelectable(row) : true);if (isSelectable) {handleClick(event, row);}}: undefined}role="checkbox"aria-checked={isItemSelected}tabIndex={-1}key={row[rowKey]}selected={isItemSelected}>{showSelect && (<TableCell padding="checkbox"><Checkboxchecked={isItemSelected}disabled={!isSelectable} // 根据 isSelectable 禁用或启用复选框inputProps={{ 'aria-labelledby': labelId }}/></TableCell>)}{columns.map((column) => (<TableCell key={`${row[rowKey]}-${column.prop}`} style={getStickyStyle(column, index)}>{column.render ? column.render(row, injectionData) : row[column?.prop]}</TableCell>))}</TableRow>);})) : (<TableRow><TableCell colSpan={columns.length + (showSelect ? 1 : 0)} align="center">{'暂无数据'}</TableCell></TableRow>)}</TableBody></Table></TableContainer>{showTablePagination && (<Box sx={{ display: 'flex', justifyContent: 'flex-start' }}><TablePaginationrowsPerPageOptions={pagination?.pageSizeOptions || [10, 20, 30, 50, 100]}component="div"count={totalCount}rowsPerPage={rowsPerPage}page={page}sx={{'.MuiTablePagination-toolbar': {alignItems: 'center', // 确保工具栏中的所有元素都垂直居中justifyContent: 'flex-end' // 工具栏内的元素靠右对齐},'.MuiTablePagination-selectLabel': {margin: 0 // 移除默认的外边距},'.MuiTablePagination-select': {margin: 0 // 移除默认的外边距},'.MuiTablePagination-displayedRows': {margin: 0 // 移除默认的外边距},marginLeft: '-7px !important'// 你可以根据需要添加更多的样式规则}}onPageChange={handleChangePage}onRowsPerPageChange={handleChangeRowsPerPage}/></Box>)}</Paper></Box>);}
);export default EnhancedTable;

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

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

相关文章

【Linux】CodeServer:云IDE部署

Code-server 是一个开源项目&#xff0c;它允许你在任何地方通过浏览器访问 Visual Studio Code&#xff08;VS Code&#xff09;编辑器。这意味着你可以在远程服务器或云端运行 VS Code&#xff0c;并通过浏览器进行编码、调试和开发&#xff0c;而不需要在本地安装 VS Code。…

Java基础(9)- Java代码笔记6

目录 一、数组常见算法 1.数组翻转 2.冒泡排序 3.二分查找 二、对象数组 1.基本使用 三、方法参数 1.基本数据类型和引用类型 2.基本数据类型做方法参数传递 3.引用数据类型做参数传递 四、命令行参数 五、其他操作 1.快速生成方法 2.快速抽代码到方法 3.debug调…

WPF中使用Echarts显示图表

在WPF中使用ECharts来显示图表&#xff0c;你需要将ECharts嵌入到WPF应用程序中。我们这里介绍两种方法显示图表&#xff1a; 目录 一、ECharts是一个基于JavaScript的开源可视化图表库&#xff0c;因此我们需要使用WebView控件来承载一个嵌入式浏览器&#xff0c;这样就可以…

如何禁止电脑访问网站

一、修改Hosts文件 找到Hosts文件&#xff1a;在Windows系统中&#xff0c;Hosts文件通常位于C:\Windows\System32\drivers\etc\目录下。 编辑Hosts文件&#xff1a;以管理员身份打开记事本或任意文本编辑器&#xff0c;然后找到并打开Hosts文件。 添加禁止访问的域名&#…

JVM1-初识JVM

目录 什么是JVM JVM的功能 解释和运行 内存管理 即时编译 Java性能低的主要原因和跨平台特性 常见的JVM 什么是JVM JVM 全称是 Java Virtual Machine&#xff0c;中文译名&#xff1a;Java虚拟机 JVM本质上是一个运行在计算机上的程序&#xff0c;它的职责是运行Java字…

HTTP 请求方法(method)介绍

目录 一、GET 二、POST 三、其他方法 3.1 PUT 3.2 DELETE 3.3 HEAD 3.4 OPTIONS 3.5 TRACE 3.6 CONNECT 3.7 PATCH 3.8 LINK 和 UNLINK&#xff08;扩展方法&#xff09; HTTP&#xff08;超文本传输协议&#xff09;定义了多种请求方法&#xff0c;如&#xff1a; …

C++对C的扩充(8.28)

1.使用C手动封装一个顺序表&#xff0c;包括成员数组1个&#xff0c;成员变量n个 代码&#xff1a; #include <iostream>using namespace std;//类型重命名 using datatype int; #define MAX 30struct seqList { private: //私有权限datatype *data; //相当于 …

AI赚钱成功案例|像素级拆解一键生成提示词 文生图 图生视频

本文背景 之前弄了个诗词转画面大师&#xff0c;就是你给个句子&#xff0c;它就能给你画面提示词&#xff0c;接着用 AI 绘图软件能生成很棒的画面&#xff0c;再把图片弄成视频&#xff0c;最后能出个不错的作品。 最近看到那些漫剪大师的作品&#xff0c;配的歌好听&#xf…

easyPOI生成的excel添加水印

项目场景&#xff1a; 需求要求生成的excel添加水印&#xff0c;这个还是第一次听到&#xff0c;于是研究了一下。 引入依赖 代码如下&#xff1a; implementation (cn.afterturn:easypoi-base:4.5.0) {exclude group: com.google.guava, module: guavaexclude group: org…

NameNode 的 Web 界面

http://127.0.0.1:50070/ 图片显示的是Hadoop的Web界面导航栏。导航栏包含以下选项&#xff1a; Hadoop&#xff1a;Hadoop的主页。Overview&#xff1a;集群的概览信息。Datanodes&#xff1a;数据节点的状态和信息。Datanode Volume Failures&#xff1a;数据节点的卷故障信…

Python——Mixin设计模式

在Python中&#xff0c;Mixin是一种设计模式&#xff0c;它允许通过继承的方式将类的方法&#xff08;或属性&#xff09;混入&#xff08;mixin&#xff09;到其他类中。Mixin主要用于在多个类之间共享代码&#xff0c;特别是当这些类之间并没有直接的继承关系&#xff0c;或者…

Java项目: 基于SpringBoot+mysql旅游网站管理系统分前后台(含源码+数据库+开题报告+PPT+毕业论文)

一、项目简介 本项目是一套基于SpringBootmysql旅游网站管理系统分前后台 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作…

二叉树展开为列表(LeetCode)

题目 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同。 解题 clas…

011.Python爬虫系列_bs4解析

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈 入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈 虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈 PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈 Oracle数…

尚硅谷Vue入门视频 笔记

尚硅谷视频&#xff1a;https://www.bilibili.com/video/BV1Zy4y1K7SH/?spm_id_from333.999.0.0&vd_sourcecec13bbe100bddfff8baf29d18ed8994 文章目录 模板语法data与el的2种写法MVVM模型事件事件修饰符事件的基本使用 计算属性简写形式 监视属性绑定样式条件渲染列表渲…

C语言回调函数和普通函数的比较

回调函数确实可以用普通函数实现&#xff0c;但它们在某些场景下提供了独特的优势和好处。以下是回调函数的一些主要优势&#xff1a; 1. 灵活性和可扩展性 回调函数允许在运行时动态地选择和调用不同的函数。这使得代码更加灵活和可扩展。例如&#xff0c;在事件驱动的编程中…

vue3+ts+vite+electron+electron-store+electron-builder打包可安装包

yarn create vite yarn add electron yarn add electron-store yarn add electron-builder 新增main.js、preload.js // main.js const { app, BrowserWindow, ipcMain, globalShortcut } require(electron) const path require(path) let store // 我们将在稍后动态导入 el…

关于几道计算机网络题的解答

2017年12月28日&#xff0c;星期四&#xff0c; 照片上的第一题中多项式的指数看不清&#xff0c;但没关系&#xff0c;就现在的情形&#xff0c;说一下大概的思路&#xff0c;参考着再结合题目中实际的参数&#xff0c;再套一遍就能把题目解出来了&#xff0c; 假设&#xf…

raksmart大带宽服务器怎么租

RAKsmart是一个提供大带宽服务器租赁服务的厂商&#xff0c;其机房遍布不同国家与地区如美国、日本、新加坡及韩国等&#xff0c;且有大陆优化和国际BGP两条线路可供选择。Rak小编下面将详细介绍如何租用RAKsmart的大带宽服务器&#xff0c;并提供一些考量因素。 1. 选择机房位…

【软件造价咨询】AI大模型能不能替代软件工程造价师完成软件造价?

当前国内外AI大模型呈现出多样化的发展态势&#xff0c;如由OpenAI开发的自然语言处理大模型GPT系列、由Google开发的基于Transformer的双向编码表示模型BERT、由百度研发的基于飞桨深度学习平台和知识增强大模型文心一言、由阿里研发的多轮对话大模型通义千问、由清华大学计算…