添加分页组件

- 实现分页导航功能
- 添加分页样式
This commit is contained in:
Leo 2025-10-20 14:07:09 +08:00
parent 269c66d1ac
commit a3561609f5
2 changed files with 330 additions and 0 deletions

View File

@ -0,0 +1,120 @@
/* 自定义分页组件样式 */
.custom-pagination {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
border-top: 1px solid #f0f0f0;
background: #fafafa;
border-radius: 0 0 6px 6px;
margin: 0 -24px -24px -24px;
padding-left: 24px;
padding-right: 24px;
}
.pagination-info {
display: flex;
align-items: center;
gap: 16px;
color: #666;
font-size: 14px;
}
.pagination-controls {
display: flex;
align-items: center;
gap: 4px;
}
.pagination-page-item {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: 1px solid #d9d9d9;
border-radius: 6px;
cursor: pointer;
margin: 0 2px;
font-size: 14px;
transition: all 0.2s ease;
background-color: #ffffff;
color: #333;
}
.pagination-page-item:hover {
background-color: #e6f7ff;
border-color: #1890ff;
color: #1890ff;
}
.pagination-page-item.active {
background-color: #1890ff;
color: #ffffff;
border-color: #1890ff;
}
.pagination-page-item.active:hover {
background-color: #40a9ff;
border-color: #40a9ff;
}
.pagination-page-item.disabled {
cursor: not-allowed;
color: #d9d9d9;
background-color: #f5f5f5;
border-color: #d9d9d9;
}
.pagination-page-item.disabled:hover {
color: #d9d9d9;
background-color: #f5f5f5;
border-color: #d9d9d9;
}
.pagination-ellipsis {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
cursor: default;
border: none;
color: #999;
}
.pagination-jumper {
display: flex;
align-items: center;
gap: 8px;
color: #666;
font-size: 14px;
}
.pagination-page-info {
min-width: 80px;
text-align: right;
color: #666;
font-size: 14px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.custom-pagination {
flex-direction: column;
gap: 16px;
align-items: stretch;
}
.pagination-info {
justify-content: center;
}
.pagination-controls {
justify-content: center;
}
.pagination-jumper {
justify-content: center;
}
}

View File

@ -0,0 +1,210 @@
/**
* 自定义分页组件
* 支持页码跳转页面大小选择等功能
*/
import React from 'react';
import { Select, Input, Button, Space, Typography } from 'antd';
import './Pagination.css';
import {
LeftOutlined,
RightOutlined,
DoubleLeftOutlined,
DoubleRightOutlined
} from '@ant-design/icons';
const { Option } = Select;
const { Text } = Typography;
const Pagination = ({
current = 1,
total = 0,
pageSize = 10,
showSizeChanger = true,
showQuickJumper = true,
showTotal = true,
onChange,
onShowSizeChange,
pageSizeOptions = ['10', '20', '50', '100'],
style = {}
}) => {
const totalPages = Math.ceil(total / pageSize);
// 计算显示的页码范围
const getVisiblePages = () => {
const pages = [];
const delta = 2; // 当前页前后显示的页数
if (totalPages <= 7) {
// 总页数较少时显示所有页码
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
// 总页数较多时显示部分页码
let start = Math.max(1, current - delta);
let end = Math.min(totalPages, current + delta);
if (current <= delta + 1) {
end = Math.min(totalPages, 2 * delta + 2);
}
if (current >= totalPages - delta) {
start = Math.max(1, totalPages - 2 * delta - 1);
}
if (start > 1) {
pages.push(1);
if (start > 2) {
pages.push('...');
}
}
for (let i = start; i <= end; i++) {
pages.push(i);
}
if (end < totalPages) {
if (end < totalPages - 1) {
pages.push('...');
}
pages.push(totalPages);
}
}
return pages;
};
// 处理页码点击
const handlePageClick = (page) => {
if (page !== current && page >= 1 && page <= totalPages) {
onChange?.(page, pageSize);
}
};
// 处理页面大小变化
const handlePageSizeChange = (newPageSize) => {
const newCurrent = Math.min(current, Math.ceil(total / newPageSize));
onShowSizeChange?.(newCurrent, newPageSize);
onChange?.(newCurrent, newPageSize);
};
// 处理快速跳转
const handleQuickJump = (e) => {
if (e.key === 'Enter') {
const page = parseInt(e.target.value, 10);
if (page >= 1 && page <= totalPages) {
handlePageClick(page);
e.target.value = '';
}
}
};
// 使用CSS类而不是内联样式
if (total === 0) return null;
return (
<div className="custom-pagination" style={style}>
{/* 左侧信息显示 */}
<div className="pagination-info">
{showTotal && (
<Text type="secondary">
{total} 条记录
</Text>
)}
{showSizeChanger && (
<Space>
<Text type="secondary">每页显示</Text>
<Select
value={pageSize}
onChange={handlePageSizeChange}
size="small"
style={{ width: '80px' }}
>
{pageSizeOptions.map(size => (
<Option key={size} value={parseInt(size, 10)}>
{size}
</Option>
))}
</Select>
<Text type="secondary"></Text>
</Space>
)}
</div>
{/* 中间页码控制 */}
<div className="pagination-controls">
{/* 首页和上一页 */}
<div
className={`pagination-page-item ${current === 1 ? 'disabled' : ''}`}
onClick={() => current !== 1 && handlePageClick(1)}
title="首页"
>
<DoubleLeftOutlined />
</div>
<div
className={`pagination-page-item ${current === 1 ? 'disabled' : ''}`}
onClick={() => current !== 1 && handlePageClick(current - 1)}
title="上一页"
>
<LeftOutlined />
</div>
{/* 页码 */}
{getVisiblePages().map((page, index) => (
<div
key={index}
className={
page === '...'
? 'pagination-ellipsis'
: `pagination-page-item ${page === current ? 'active' : ''}`
}
onClick={() => page !== '...' && handlePageClick(page)}
>
{page}
</div>
))}
{/* 下一页和末页 */}
<div
className={`pagination-page-item ${current === totalPages ? 'disabled' : ''}`}
onClick={() => current !== totalPages && handlePageClick(current + 1)}
title="下一页"
>
<RightOutlined />
</div>
<div
className={`pagination-page-item ${current === totalPages ? 'disabled' : ''}`}
onClick={() => current !== totalPages && handlePageClick(totalPages)}
title="末页"
>
<DoubleRightOutlined />
</div>
</div>
{/* 右侧快速跳转 */}
<div className="pagination-jumper">
{showQuickJumper && (
<Space>
<Text type="secondary">跳至</Text>
<Input
size="small"
style={{ width: '50px' }}
placeholder=""
onKeyPress={handleQuickJump}
/>
<Text type="secondary"></Text>
</Space>
)}
<div className="pagination-page-info">
<Text type="secondary">
{current} / {totalPages}
</Text>
</div>
</div>
</div>
);
};
export default Pagination;