当前位置: 首页> 汽车> 时评 > React+TS前台项目实战(十六)-- 全局常用组件Pagination封装

React+TS前台项目实战(十六)-- 全局常用组件Pagination封装

时间:2025/7/10 10:04:39来源:https://blog.csdn.net/weixin_43883615/article/details/139886349 浏览次数: 1次

文章目录

  • 前言
  • Pagination组件
    • 1. 功能分析
    • 2. 代码+详细注释
    • 3. 使用方式
    • 4. 效果展示 [PC端&手机端]
  • 总结


前言

在上篇文章中,我们封装了表格组件Table,本文则继续封装配套使用的分页器组件。想看Table表格组件的,可自行查看全局常用组件Table封装


Pagination组件

1. 功能分析

(1)渲染一个带有分页功能的用户界面,包括导航到第一页、上一页、下一页和最后一页的按钮,并实现响应式布局
(2)提供一个输入框,允许用户手动输入页码,并提供一个按钮用于跳转到指定页码
(3)通过调用onChange prop来更新页码,并根据当前页数更新UI显示
(4)通过自定义的useIsMobile hook来判断设备类型,根据设备类型显示不同效果
(5)使用国际化语言显示文案

2. 代码+详细注释

// @/components/Pagination/index.tsx
import { useState, FC } from 'react'
import { useTranslation } from 'react-i18next'
import { PaginationLeft, PaginationRight, PaginationContainer } from './styled'
import { useIsMobile } from '@/hooks'
import Button from '@/components/Button'
import LeftArrow from './left_arrow.png'
import RightArrow from './right_arrow.png'
import DisLeftArrow from './disabled_left_arrow.png'
import DisRightArrow from './disabled_right_arrow.png'// 组件的属性类型
type Props = {currentPage: number // 当前页码total: number // 总页数gotoPage?: number // 跳转页码,默认为当前页码加一onChange: (page: number, size?: number) => void // 页码改变时的回调函数className?: string // 组件额外的class名pageSize?: number // 每页显示条目数pageSizes?: number[] // 每页显示条目数的可选项
}/*** 分页组件* @param currentPage 当前页码* @param total 总页数* @param gotoPage 跳转页码,默认为当前页码加一* @param onChange 页码改变时的回调函数* @param className 组件额外的class名* @param pageSize 每页显示条目数* @param pageSizes 每页显示条目数的可选项*/
const Pagination: FC<Props> = ({currentPage,total,gotoPage = currentPage === total ? total : currentPage + 1,onChange,className,pageSize,pageSizes,
}) => {// 判断是否是移动端const isMobile = useIsMobile()// 获取i18n翻译函数const { t } = useTranslation()// 创建一个state,用于存储输入框的值const [inputVal, setInputVal] = useState(gotoPage)// 计算总页数,并确保总页数大于0const totalCount = Math.max(total, 1)// 计算当前页数,并确保当前页数在范围内const current = Math.min(Math.max(currentPage, 1), total)// 移动端中间描述文本const mobileMiddleDescrip = `${t('pagination.total_page')} ${totalCount} ${t('pagination.end_page')}`// PC端中间描述文本const pcMiddleDescrip = `${t('pagination.current_page')} ${current} ${t('pagination.of_page')} ${totalCount} ${t('pagination.end_page',)}`// 页码更新const changePage = (page: number) => {if (page && page >= 1 && page <= totalCount) {setInputVal(Math.min(page + 1, totalCount))onChange(page)}}return (<PaginationContainer className={className}><PaginationLeft isFirstPage={current === 1} isLastPage={current === totalCount}><Button className="first-button" onClick={() => changePage(1)}>{t('pagination.first')}</Button><Button className="left-button" onClick={() => changePage(current - 1)}><img src={current === 1 ? DisLeftArrow : LeftArrow} alt="左侧按钮" /></Button>{!isMobile && <span className="middle-discrip">{pcMiddleDescrip}</span>}<Button className="right-button" onClick={() => changePage(current + 1)}><img src={current === totalCount ? DisRightArrow : RightArrow} alt="右侧按钮" /></Button>{isMobile && <span className="middle-discrip">{mobileMiddleDescrip}</span>}<Button className="last-button" onClick={() => changePage(totalCount)}>{t('pagination.last')}</Button></PaginationLeft><PaginationRight><span className="page-label">{t('pagination.page')}</span><inputtype="text"className="page-input"pattern="[0-9]*"value={inputVal}onChange={event => {const pageNo = parseInt(event.target.value, 10)setInputVal(Number.isNaN(pageNo) ? 0 : Math.min(pageNo, totalCount))}}/><Button className="page-go-to" onClick={() => changePage(inputVal)}>{t('pagination.goto')}</Button></PaginationRight></PaginationContainer>)
}export default Pagination
--------------------------------------------------------------------------------------------------------------
// @/components/Pagination/styled.tsx
import styled from 'styled-components'
import variables from '../../styles/variables.module.scss'
export const PaginationContainer = styled.div`display: flex;flex-direction: row;padding: 10px 20px;background: #fff;
`
export const PaginationLeft = styled.div`display: flex;align-items: center;justify-content: center;flex: 3;font-size: 14px;@media (max-width: ${variables.mobileBreakPoint}) {padding-left: 0;justify-content: flex-start;}.first-button,.last-button {padding: 4px 8px;border-radius: 5px;background: #f5f5f5;cursor: pointer;color: ${({ isFirstPage }: { isFirstPage: boolean }) => (isFirstPage ? '#969696' : '#000000')};cursor: ${({ isFirstPage }: { isFirstPage: boolean }) => (isFirstPage ? 'pointer' : 'auto')};&:hover {background: #999;}@media (max-width: ${variables.mobileBreakPoint}) {display: none;}}.left-button,.right-button {margin-left: 20px;width: 30px;height: 30px;display: flex;align-items: center;justify-content: center;border-radius: 5px;background: #f5f5f5;cursor: ${({ isFirstPage }: { isFirstPage: boolean }) => (isFirstPage ? 'pointer' : 'auto')};&:hover {background: #999;}img {width: 8px;}@media (max-width: ${variables.mobileBreakPoint}) {margin-left: 5px;}}.right-button {cursor: ${({ isLastPage }: { isLastPage: boolean }) => (isLastPage ? 'pointer' : 'auto')};}.last-button {margin-left: 20px;color: ${({ isLastPage }: { isLastPage: boolean }) => (isLastPage ? '#969696' : '#000000')};cursor: ${(props: { isFirstPage: boolean; isLastPage: boolean }) => (props.isLastPage ? 'none' : 'auto')};}.middle-discrip {display: flex;align-items: center;justify-content: center;height: 30px;background: #f5f5f5;border-radius: 5px;font-size: 12px;padding: 0 12px;margin-left: 20px;white-space: nowrap;@media (max-width: ${variables.mobileBreakPoint}) {background: #fff;border-radius: 0;margin: 0 5px;padding: 0;}}
`export const PaginationRight = styled.div`display: flex;align-items: center;flex: 2;font-size: 14px;@media (max-width: ${variables.mobileBreakPoint}) {justify-content: flex-end;}.page-input {width: 120px;height: 30px;border-radius: 5px;background-color: rgb(245, 245, 245);color: rgb(204, 204, 204);margin-right: 40px;outline: none;border: none;padding-left: 10px;@media (max-width: ${variables.mobileBreakPoint}) {width: 60px;margin-right: 20px;font-size: 12px;}}.page-label {margin-right: 20px;@media (max-width: ${variables.mobileBreakPoint}) {display: none;}}.page-go-to {height: 30px;line-height: 30px;padding: 0 10px;background: #f5f5f5;border-radius: 6px;border: none;outline: none;cursor: pointer;&:hover {background: #999;}@media (max-width: ${variables.mobileBreakPoint}) {font-size: 12px;}}
`

3. 使用方式

// 引入组件
import Pagination from "@/components/Pagination";
// 使用
<PaginationcurrentPage={1}PageSize={10}PageSizes={[10, 20, 30]}total={data?.total ?? 1}onChange={handlePageChange}
/>
const handlePageChange = (page: number) => {console.log('handlePageChange', page)
}

4. 效果展示 [PC端&手机端]

(1)PC端
在这里插入图片描述
(2)手机端
在这里插入图片描述


总结

下一篇讲【开始首页编码教学】。关注本栏目,将实时更新。

关键字:React+TS前台项目实战(十六)-- 全局常用组件Pagination封装

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: