Files
vf_react/src/views/Community/components/DynamicNewsCard/PaginationControl.js
2025-11-05 17:08:01 +08:00

216 lines
5.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/views/Community/components/DynamicNewsCard/PaginationControl.js
// 分页控制器组件
import React, { useState } from 'react';
import {
Box,
HStack,
Button,
Input,
Text,
IconButton,
useColorModeValue,
useToast,
} from '@chakra-ui/react';
import {
ChevronLeftIcon,
ChevronRightIcon,
} from '@chakra-ui/icons';
/**
* 分页控制器组件(使用 React.memo 优化,避免不必要的重新渲染)
* @param {number} currentPage - 当前页码
* @param {number} totalPages - 总页数
* @param {Function} onPageChange - 页码改变回调
*/
const PaginationControl = React.memo(({ currentPage, totalPages, onPageChange }) => {
const [jumpPage, setJumpPage] = useState('');
const toast = useToast();
const buttonBg = useColorModeValue('white', 'gray.700');
const activeBg = useColorModeValue('blue.500', 'blue.400');
const activeColor = useColorModeValue('white', 'white');
const borderColor = useColorModeValue('gray.300', 'gray.600');
const hoverBg = useColorModeValue('gray.100', 'gray.600');
// 生成页码数字列表(智能省略)
const getPageNumbers = () => {
const pageNumbers = [];
const maxVisible = 5; // 最多显示5个页码精简版
if (totalPages <= maxVisible) {
// 总页数少,显示全部
for (let i = 1; i <= totalPages; i++) {
pageNumbers.push(i);
}
} else {
// 总页数多,使用省略号
if (currentPage <= 3) {
// 当前页在前面
for (let i = 1; i <= 4; i++) {
pageNumbers.push(i);
}
pageNumbers.push('...');
pageNumbers.push(totalPages);
} else if (currentPage >= totalPages - 2) {
// 当前页在后面
pageNumbers.push(1);
pageNumbers.push('...');
for (let i = totalPages - 3; i <= totalPages; i++) {
pageNumbers.push(i);
}
} else {
// 当前页在中间
pageNumbers.push(1);
pageNumbers.push('...');
pageNumbers.push(currentPage);
pageNumbers.push('...');
pageNumbers.push(totalPages);
}
}
return pageNumbers;
};
// 处理页码跳转
const handleJump = () => {
const page = parseInt(jumpPage, 10);
if (isNaN(page)) {
toast({
title: '请输入有效的页码',
status: 'warning',
duration: 2000,
isClosable: true,
});
return;
}
if (page < 1 || page > totalPages) {
toast({
title: `页码范围1 - ${totalPages}`,
status: 'warning',
duration: 2000,
isClosable: true,
});
return;
}
onPageChange(page);
setJumpPage('');
};
// 处理回车键
const handleKeyPress = (e) => {
if (e.key === 'Enter') {
handleJump();
}
};
const pageNumbers = getPageNumbers();
return (
<Box mb={3}>
<HStack spacing={1.5} justify="center" flexWrap="wrap">
{/* 上一页按钮 */}
<IconButton
icon={<ChevronLeftIcon />}
size="xs"
onClick={() => onPageChange(currentPage - 1)}
isDisabled={currentPage === 1}
bg={buttonBg}
borderWidth="1px"
borderColor={borderColor}
_hover={{ bg: hoverBg }}
aria-label="上一页"
title="上一页"
/>
{/* 数字页码列表 */}
{pageNumbers.map((page, index) => {
if (page === '...') {
return (
<Text
key={`ellipsis-${index}`}
px={1}
fontSize="xs"
color="gray.500"
>
...
</Text>
);
}
return (
<Button
key={page}
size="xs"
onClick={() => onPageChange(page)}
bg={currentPage === page ? activeBg : buttonBg}
color={currentPage === page ? activeColor : undefined}
borderWidth="1px"
borderColor={currentPage === page ? activeBg : borderColor}
_hover={{
bg: currentPage === page ? activeBg : hoverBg,
}}
minW="28px"
>
{page}
</Button>
);
})}
{/* 下一页按钮 */}
<IconButton
icon={<ChevronRightIcon />}
size="xs"
onClick={() => onPageChange(currentPage + 1)}
isDisabled={currentPage === totalPages}
bg={buttonBg}
borderWidth="1px"
borderColor={borderColor}
_hover={{ bg: hoverBg }}
aria-label="下一页"
title="下一页"
/>
{/* 分隔线 */}
<Box w="1px" h="20px" bg={borderColor} mx={1.5} />
{/* 输入框跳转 */}
<HStack spacing={1.5}>
<Text fontSize="xs" color="gray.600">
跳转到
</Text>
<Input
size="xs"
width="50px"
type="number"
min={1}
max={totalPages}
value={jumpPage}
onChange={(e) => setJumpPage(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="页"
bg={buttonBg}
borderColor={borderColor}
/>
<Button
size="xs"
colorScheme="blue"
onClick={handleJump}
>
跳转
</Button>
</HStack>
</HStack>
</Box>
);
}, (prevProps, nextProps) => {
// 自定义比较函数:只有当 currentPage 或 totalPages 变化时才重新渲染
return prevProps.currentPage === nextProps.currentPage &&
prevProps.totalPages === nextProps.totalPages;
});
export default PaginationControl;