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

文章目录

  • 前言
  • 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)
  // 计算总页数,并确保总页数大于0
  const 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>
        <input
          type="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";
// 使用
<Pagination
  currentPage={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)手机端
在这里插入图片描述


总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/746542.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【渗透测试】小程序反编译

前言 在渗透测试时&#xff0c;除了常规的Web渗透&#xff0c;小程序也是我们需要重点关注的地方&#xff0c;微信小程序反编译后&#xff0c;可以借助微信小程序开发者工具进行调试&#xff0c;搜索敏感关键字&#xff0c;或许能够发现泄露的AccessKey等敏感信息及数据 工具…

工业液晶屏G065VN01 V2规格书简介

G065VN01 V2 背面实物图 2. 概述 G065VN01 V2 专为 VGA &#xff08;640 x RGB x 480&#xff09; 分辨率和 16.2M&#xff08;RGB 6 位 FRC&#xff09;或 262k 色&#xff08;RGB 6 位&#xff09;的工业显示应用而设计。它由TFT-LCD面板、驱动IC、控制和电源电路板以及包括…

按位与、或、异或操作符

目录 & --- 按位与操作符 按位与操作符运用规则 按位与操作符相关代码 按位与操作符相关代码验证 | --- 按位或操作符 按位或操作符运用规则 按位或操作符相关代码 按位或操作符相关代码验证 ^ --- 按位异或操作符 按位异或操作符运用规则 按位异或操作符相关代…

[AI开发配环境]VSCode远程连接ssh服务器

文章目录 总览&#xff1a;ssh连接远程服务器连接免密登录&#xff1a;Docker&#xff1a;ssh连接远程宿主机后&#xff0c;进一步连接并使用其中的docker容器reload window 配置解释器&#xff1a;CtrlP&#xff0c;在上面输入“>python”, 然后选selecet interpreter运行命…

ubuntu如何切换到root用户

1、主要指令&#xff1a; sudo -i su root 2、示例 3、其他说明 在Ubuntu&#xff08;以及大多数其他基于Linux的操作系统中&#xff09;&#xff0c;切换到root用户通常意味着获得了对系统的完全访问权限。这种权限允许执行以下操作&#xff08;但不限于这些&#xff09;…

【C语言】解决C语言报错:Double Free

文章目录 简介什么是Double FreeDouble Free的常见原因如何检测和调试Double Free解决Double Free的最佳实践详细实例解析示例1&#xff1a;重复调用free函数示例2&#xff1a;多次释放全局变量指针示例3&#xff1a;函数间传递和释放指针 进一步阅读和参考资料总结 简介 Doub…

【ajax实战03】拦截器

一&#xff1a;axios拦截器 拦截器分类&#xff1a; 请求拦截器以及响应拦截器 拦截器作用&#xff1a; 在请求或响应被then或catch处理前拦截它们 二&#xff1a;请求拦截器 作用&#xff1a; 发起请求之前&#xff0c;调用一个配置函数&#xff0c;对请求参数进行设置…

MyBatis案例

目录 一、配置文件1.数据与环境准备1.1 创建tb_brand表1.2 在Pojo中创建实体类Brand.java1.3 在test文件夹下的java中创建测试类1.4 安装MyBatisX插件 二、增删改查1. 查询 一、配置文件 1.数据与环境准备 1.1 创建tb_brand表 -- 删除tb_brand表 drop table if exists tb_bra…

什么是大模型?一文读懂大模型的基本概念

大模型是指具有大规模参数和复杂计算结构的机器学习模型。本文从大模型的基本概念出发&#xff0c;对大模型领域容易混淆的相关概念进行区分&#xff0c;并就大模型的发展历程、特点和分类、泛化与微调进行了详细解读&#xff0c;供大家在了解大模型基本知识的过程中起到一定参…

【Qt】初识QtQt Creator

一.简述Qt 1.什么是Qt Qt 是⼀个 跨平台的 C 图形⽤⼾界⾯应⽤程序框架 。它为应⽤程序开发者提供了建⽴艺术级图形界⾯所需的所有功能。它是完全⾯向对象的&#xff0c;很容易扩展。Qt 为开发者提供了⼀种基于组件的开发模式&#xff0c;开发者可以通过简单的拖拽和组合来实现…

Energy-based PINN在固体力学中的运用

简介 物理信息神经网络&#xff08;Physic informed neural network&#xff0c;PINN&#xff09;已经成为在有限差分、有限体积和有限元之后的另一种求解偏微分方程组的范式&#xff0c;受到学者们广泛关注。 在固体力学领域有两类不同的PINN: &#xff08;1&#xff09;PDE…

mac卡牌游戏:堆叠大陆 Stacklands for Mac 中文安装包

Stacklands 是一款轻松益智的堆叠游戏。玩家需要在游戏中不断堆叠不同形状和大小的方块&#xff0c;使它们尽可能地稳定地堆放在一起。游戏中有多种不同的关卡和挑战&#xff0c;玩家需要通过合理的堆叠方式来完成每个关卡。游戏画面简洁明快&#xff0c;操作简单直观&#xff…

跟我从零开始学C++(C++代码基础)5

引言 小伙伴们&#xff0c;在经过一些基础定义和指针&#xff0c;数组&#xff0c;函数的洗礼后&#xff0c;我相信大家肯定都已经对C编程有了新的认知&#xff0c;同时呢&#xff0c;坚持下来的小伙伴们肯定都是好样的&#xff0c;大家都是很棒的&#xff0c;现在我们来学一学…

开源模型应用落地-FastAPI-助力模型交互-WebSocket篇(二)

一、前言 使用 FastAPI 可以帮助我们更简单高效地部署 AI 交互业务。FastAPI 提供了快速构建 API 的能力,开发者可以轻松地定义模型需要的输入和输出格式,并编写好相应的业务逻辑。 FastAPI 的异步高性能架构,可以有效支持大量并发的预测请求,为用户提供流畅的交互体验。此外,F…

Leetcode Hot100之矩阵

1. 矩阵置零 题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 解题思路 题目要求进行原地更改&#xff0c;也就是不能使用额外的空间&#xff0c;因此我们可以使用第一行的元素来记录对应的…

【软件下载】Folx详细安装教程视频-Folx软件最新版下载

根据大数据调查表明Acceleration PRO下载&#xff1a;抽出多达10个流的故障能够显着提高下载速度。根据行业数据显示与iTunes PRO集成&#xff1a;通过将Folx集成到iTunes来下载歌曲和视频&#xff0c;能够在下载后立即自动添加到iTunes库。实际上我们可以这样讲通过代理下载&a…

Git 冲突处理指南:恢复 Git Reset

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

10个AI高考上岸朋友圈文案设计

高考是人生中的一个重要时刻&#xff0c;上岸后分享朋友圈的文案可以既表达喜悦&#xff0c;也可以展现对未来的期待。以下是10个不同风格的高考上岸朋友圈文案&#xff0c;供你参考&#xff1a; 1. **梦想成真版**&#xff1a; "十年磨一剑&#xff0c;今朝试锋芒。高…

After Effects 2024 mac/win版:创意视效,梦想起航

After Effects 2024是一款引领视效革命的专业软件&#xff0c;汇聚了创意与技术的精华。作为Adobe推出的全新版本&#xff0c;它以其强大的视频处理和动画创作能力&#xff0c;成为从事设计和视频特技的机构&#xff0c;如电视台、动画制作公司、个人后期制作工作室以及多媒体工…

【Linux】进程信号_2

文章目录 八、进程信号1. 信号 未完待续 八、进程信号 1. 信号 除了可以使用 kill 命令和键盘来生成信号&#xff0c;我们也可以使用系统调用来生成信号。 kill函数可以对指定进程发送指定信号。 使用方法&#xff1a; int main(int argc, char *argv[]) {if (argc ! 3) {c…