目录 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 } = 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) ; } ; } ; 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' 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) ; } ; 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' , 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;