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


前言

在上篇文章中,我们封装了表格组件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)手机端
在这里插入图片描述


总结

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

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作为前端使用React、TypeScript、React Router、Redux、Axios、Ant Design和Sass开发ERP软件项目的职责描述,主要包括以下几个方面: 1. 分析需求和设计界面:与产品经理、设计师等团队成员合作,分析用户需求和产品设计,设计符合用户需求的界面,并提供良好的用户体验。 2. 使用React和TypeScript开发组件:根据设计稿或需求文档,使用React和TypeScript开发可复用的组件,利用类型检查提高代码的可靠性和可维护性。 3. 使用React Router实现路由管理:使用React Router进行页面之间的导航和路由管理,确保页面之间的跳转和参数传递的正常。 4. 使用Redux进行状态管理:使用Redux进行全局状态的管理,包括定义和处理数据流、异步操作、状态持久化等,确保数据的一致性和可控性。 5. 使用Axios进行网络请求:使用Axios库发送HTTP请求与后端API进行数据交互,并处理请求的错误和异常情况。 6. 使用Ant Design进行UI开发:使用Ant Design提供的组件库进行界面开发,保证界面的一致性和美观性,并根据需求进行自定义样式。 7. 使用Sass进行样式管理:使用Sass预处理器编写可复用的样式代码,提高样式开发效率,并保持样式的可维护性。 8. 优化性能和用户体验:通过前端优化技术(如代码分割、懒加载、缓存等),提升ERP软件的性能和用户体验,确保页面加载速度快、操作流畅。 9. 跨浏览器兼容性测试:测试并确保ERP软件在各种主流浏览器(如Chrome、Firefox、Safari等)下的正常运行,并解决兼容性问题。 10. 代码版本管理和团队协作:使用版本管理工具(如Git)管理代码,与团队成员协作开发,参与代码评审和项目迭代。 11. 系统维护和故障排除:及时响应用户反馈并解决软件中出现的前端问题,修复bug,确保ERP软件的稳定运行。 总的来说,前端使用React、TypeScript、React Router、Redux、Axios、Ant Design和Sass开发ERP软件项目的职责是负责开发和维护ERP软件的前端界面和功能,与后端进行数据交互,优化性能和用户体验,并与团队成员协作推动项目的成功交付。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值