组件实现
src\components\Table\index.tsx
文件
import React, { useMemo, useState } from 'react';
import './index.less';
type NodeType = string | React.ReactNode | ((item?: any) => React.ReactNode);
interface HeaderItem {
/* 列key */
key: string;
/* 渲染头部 */
header: NodeType;
/* 渲染数据 */
render?: (item: any) => React.ReactNode;
}
interface TableProps {
/* 列表数据 */
data: any[];
/* 头部数据 */
column: HeaderItem[];
/* 列表数量 */
total: number;
/* 当前页码 */
pageIndex?: number;
/* 当前页显示条数 */
pageSize?: number;
/* 页条数数组 */
sizeList?: number[];
/* 样式 */
style?: React.CSSProperties;
/* 类名 */
className?: string;
/* 行内点击事件 */
handleRow?: React.MouseEventHandler;
/* 分页 */
onChangePage?: (pageIndex: number, pageSize: number) => void;
/* 排序 */
handleSort?: (key: string, sort: 'desc' | 'asd' | '') => void;
}
export default function Table(props: TableProps) {
const {
data,
column,
total,
style,
className,
pageIndex,
pageSize,
sizeList,
onChangePage,
} = props;
// 当前页
const [currentPageIndex, setCurrentPageIndex] = useState(pageIndex || 1);
// 当前页码显示数量
const [currentPageSize, setCurrentPageSize] = useState(pageSize || 5);
// 计算当前页数
const pageCount = (total: number, size: number) => {
return (total / size).toString().includes('.') ? Math.floor(total / size) + 1 : Math.floor(total / size)
}
// 总页码数
const [page, setPage] = useState(pageCount(total, currentPageSize));
// console.log('page', page, currentPageIndex);
// 表头渲染
const renderOrderByType = (content: NodeType) => {
let type = 'string';
let result = content;
if (typeof content === 'string') {
type = 'string';
result = content;
} else if (content instanceof Function) {
type = 'function';
result = content();
} else {
type = 'element';
result = content;
}
return result;
}
// 数据渲染逻辑
const renderDataItemType = (key: string, dataItem: any, render?: (item: any) => React.ReactNode) => {
if (render === undefined) {
return dataItem[key]
} else {
return render(dataItem)
}
}
// 渲染表头
const renderColumn: JSX.Element = useMemo(() => {
return (
<>
<tr>
{
column?.map((item, index: number) => {
return (
<React.Fragment key={index}>
<th >
{renderOrderByType(item.header)}
</th>
</React.Fragment>
)
})
}
</tr>
</>
)
}, [column])
// 列表数据渲染
const renderTableList: JSX.Element = useMemo(() => {
return (
<>
{
data?.map((dataItem, dataIndex: number) => {
return <React.Fragment key={dataIndex}>
<tr>
{
column?.map((colItem, colIndex) => {
return (
<React.Fragment key={colIndex}>
<td >
{renderDataItemType(colItem.key, dataItem, colItem.render)}
</td>
</React.Fragment>
)
})
}
</tr>
</React.Fragment>
})
}
</>
)
}, [data, column])
// 切换上一页下一页或每页条数
const handlePage = (type: string, value?: number) => {
let pageIndex = currentPageIndex;
let pageSize = currentPageSize;
switch (type) {
case 'pre':
pageIndex = pageIndex -1
setCurrentPageIndex(pageIndex);
break;
case 'next':
pageIndex = pageIndex + 1
setCurrentPageIndex(pageIndex);
break;
case 'itemCount':
pageIndex = 1;
pageSize = Number(value) || currentPageSize;
setCurrentPageIndex(1);
setCurrentPageSize(pageSize)
setPage(pageCount(total, pageSize));
break;
}
onChangePage && onChangePage?.(pageIndex, pageSize)
}
return (
<div className='H-Table'>
<table className='H-Table-inner'>
<thead className='H-Table-header'>
{renderColumn}
</thead>
<tbody className='H-Table-body'>
{
renderTableList
}
</tbody>
</table>
<div className='H-Table-page'>
<span className='show'>共{total}条</span>
<div className='operation'>
<select className=' item' onChange={(e) =>{
handlePage('itemCount',Number(e.target.value))
}}>
<option value="5">5</option>
<option value="10">10</option>
</select>
<button
className={`${currentPageIndex === 1 ? 'disabled-item item' : 'item'}`}
onClick={() => handlePage('pre')}
disabled={currentPageIndex === 1}
>
上一个
</button>
<button
className={`${page === currentPageIndex ? 'disabled-item item' : 'item'}`}
onClick={() => handlePage('next')}
disabled={page === currentPageIndex}
>
下一页
</button>
</div>
</div>
</div>
)
}
src\components\Table\index.less
文件
.H-Table {
text-align: left;
&-inner {
width: 100%;
}
&-header {
border-bottom: 1px solid #e7eaef;
th {
height: 46px;
}
}
&-body {
td {
height: 42px;
box-sizing: content-box;
}
}
&-page {
border-top: 1px solid #e7eaef;
height: 60px;
line-height: 60px;
display: flex;
justify-content: space-between;
margin: auto 20px;
.item {
margin-left: 10px;
height: 40px;
line-height: 30px;
border: 1px solid #e7eaef;
padding: 4px;
cursor: pointer;
}
.disabled-item {
cursor: not-allowed;
}
}
}
组件使用
src\pages\index.tsx
文件
import React, { useState, useEffect, useRef } from 'react';
import './index.less';
import Table from '@/components/Table';
const dataList = [
{
id: '1',
count: 30,
rank: 98
},
{
id: '2',
count: 30,
rank: 98
},
{
id: '3',
count: 30,
rank: 98
},
{
id: '4',
count: 30,
rank: 98
},
{
id: '5',
count: 30,
rank: 98
},
{
id: '6',
count: 30,
rank: 98
},
{
id: '7',
count: 30,
rank: 98
},
{
id: '8',
count: 30,
rank: 98
},
{
id: '9',
count: 30,
rank: 98
},
{
id: '10',
count: 30,
rank: 98
},
{
id: '11',
count: 30,
rank: 98
},
{
id: '12',
count: 30,
rank: 98
}
]
const ColumnList = [
{
key: 'id',
header: 'ID'
},
{
key: 'count',
header: () => {
return (
<span>Count</span>
)
},
render: (ctx) => {
return <span>{`${ctx.count} 个`}</span>
}
}, {
key: 'rank',
header: <span>Rank</span>,
render: (ctx) => {
return (
<>
<p>{`${ctx.rank}级别`}</p>
<div>详细查看</div>
</>
)
}
}
]
export default function IndexPage() {
const [tableList, setTableList] = useState(dataList.slice(0, 5))
return (
<div className="indexPage" >
<div>
<Table
data={tableList}
column={ColumnList}
total={12}
onChangePage={(pageIndex: number, pageSize: number) => {
console.log('onChangePage', pageIndex, pageSize);
setTableList(dataList.slice((pageIndex - 1) * pageSize, pageIndex * pageSize))
}}
/>
</div>
</div>
);
}