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

2024-08-31 08:28

本文主要是介绍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;

这篇关于react + ts + material-ui V5版本的table封装的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1123382

相关文章

IDEA如何切换数据库版本mysql5或mysql8

《IDEA如何切换数据库版本mysql5或mysql8》本文介绍了如何将IntelliJIDEA从MySQL5切换到MySQL8的详细步骤,包括下载MySQL8、安装、配置、停止旧服务、启动新服务以及... 目录问题描述解决方案第一步第二步第三步第四步第五步总结问题描述最近想开发一个新应用,想使用mysq

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

Debian如何查看系统版本? 7种轻松查看Debian版本信息的实用方法

《Debian如何查看系统版本?7种轻松查看Debian版本信息的实用方法》Debian是一个广泛使用的Linux发行版,用户有时需要查看其版本信息以进行系统管理、故障排除或兼容性检查,在Debia... 作为最受欢迎的 linux 发行版之一,Debian 的版本信息在日常使用和系统维护中起着至关重要的作

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

Python中的可视化设计与UI界面实现

《Python中的可视化设计与UI界面实现》本文介绍了如何使用Python创建用户界面(UI),包括使用Tkinter、PyQt、Kivy等库进行基本窗口、动态图表和动画效果的实现,通过示例代码,展示... 目录从像素到界面:python带你玩转UI设计示例:使用Tkinter创建一个简单的窗口绘图魔法:用

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

element-ui下拉输入框+resetFields无法回显的问题解决

《element-ui下拉输入框+resetFields无法回显的问题解决》本文主要介绍了在使用ElementUI的下拉输入框时,点击重置按钮后输入框无法回显数据的问题,具有一定的参考价值,感兴趣的... 目录描述原因问题重现解决方案方法一方法二总结描述第一次进入页面,不做任何操作,点击重置按钮,再进行下

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

你的华为手机升级了吗? 鸿蒙NEXT多连推5.0.123版本变化颇多

《你的华为手机升级了吗?鸿蒙NEXT多连推5.0.123版本变化颇多》现在的手机系统更新可不仅仅是修修补补那么简单了,华为手机的鸿蒙系统最近可是动作频频,给用户们带来了不少惊喜... 为了让用户的使用体验变得很好,华为手机不仅发布了一系列给力的新机,还在操作系统方面进行了疯狂的发力。尤其是近期,不仅鸿蒙O

什么是 Ubuntu LTS?Ubuntu LTS和普通版本区别对比

《什么是UbuntuLTS?UbuntuLTS和普通版本区别对比》UbuntuLTS是Ubuntu操作系统的一个特殊版本,旨在提供更长时间的支持和稳定性,与常规的Ubuntu版本相比,LTS版... 如果你正打算安装 Ubuntu 系统,可能会被「LTS 版本」和「普通版本」给搞得一头雾水吧?尤其是对于刚入