目录
1:react中hook封装一个table组件 依赖 CommonTable / index.tsx 使用组件 效果
2:useColumns组件
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;
}
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) ;
} ;
} ;
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) ;
} ;
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' ,
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;
效果
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 (
< span
onClick= { ( e ) => handleEvent ( '编辑' , record, e) }
className= "check-btn"
>
编辑
< / span>
) ;
} else {
return (
< span
onClick= { ( 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 (
< >
< CommonTable
rowKey= { 'id' }
className= { classes. table}
dataSource= { testData}
scroll= { {
x : 'max-content' ,
} }
columns= { useColumns ( { handleSeeDetail, handleEdit } ) }
/ >
< / >
) ;
} ;
export default TablePage;