import React, { useState, useEffect } from "react"; import classNames from "classnames"; import { StyledProps } from "../_type"; import { Icon } from "../icon"; import { Tooltip } from "../tooltip"; import { useTranslation } from "../i18n"; import { Select } from "../select"; import { useConfig } from "../_util/config-context"; import { noop } from "../_util/noop"; import { KeyMap } from "../_util/key-map"; /** * 表示分页信息 */ export interface PagingQuery { /** * 页码:从 1 开始索引 */ pageIndex?: number; /** * 页长:表示每页记录数 */ pageSize?: number; } export interface PaginationProps extends Partial, StyledProps { /** * 必传,数据总个数,用于计算页数 */ recordCount: number; /** * 切换分页回调函数 */ onPagingChange?: (query: PagingQuery) => void; /** * 切换页长时,是否自动把页码重设为 1 * @default true */ isPagingReset?: boolean; /** * 页组件显示的说明信息,不传将渲染数据个数信息 */ stateText?: React.ReactNode; /** * 支持的页长设置 * @default [10, 20, 30, 50, 100, 200] */ pageSizeOptions?: number[]; /** * 是否显示状态文案 * @default true */ stateTextVisible?: boolean; /** * 是否显示页长选择 * @default true */ pageSizeVisible?: boolean; /** * 是否显示页码输入 * @default true */ pageIndexVisible?: boolean; /** * 是否显示切页按钮(上一页/下一页) * @default true */ jumpVisible?: boolean; /** * 是否显示第一页和最后一页按钮 * @default true */ endJumpVisible?: boolean; /** * 当前页码大于总页数时的自动重置行为 * * 重置类型:不处理 / 回到首页 / 回到可用的末页 * * @default "unset" * @since 2.6.3 */ pageCountChangingResetType?: "unset" | "first" | "last"; } export const defaultPageSizeOptions = [10, 20, 30, 50, 100, 200]; export const Pagination = React.forwardRef(function Pagination( { pageIndex, pageSize, pageSizeOptions, recordCount, onPagingChange = noop, isPagingReset = true, stateText, stateTextVisible, pageSizeVisible, pageIndexVisible, jumpVisible, endJumpVisible, className, pageCountChangingResetType = "unset", ...props }: PaginationProps, ref: React.Ref ) { const { classPrefix } = useConfig(); const t = useTranslation(); if (!Array.isArray(pageSizeOptions) || pageSizeOptions.length === 0) { pageSizeOptions = defaultPageSizeOptions; // eslint-disable-line no-param-reassign } // 为非受控组件提供状态管理 const [internalPaging, setInternalPaging] = useState({ pageIndex: 1, pageSize: pageSizeOptions[0], }); // 非受控组件,使用内部状态 if (typeof pageIndex === "undefined") { // eslint-disable-next-line prefer-destructuring,no-param-reassign pageIndex = internalPaging.pageIndex; } if (typeof pageSize === "undefined") { // eslint-disable-next-line prefer-destructuring,no-param-reassign pageSize = internalPaging.pageSize; } // 状态改变同时更新内部状态和通知外部 // eslint-disable-next-line no-param-reassign onPagingChange = (onPagingChange => (query: PagingQuery) => { setInternalPaging(query); onPagingChange(query); })(onPagingChange); // 总页数 const pageCount = Math.max(1, Math.ceil(recordCount / pageSize)); // 改变页长 const changePageSize = (pageSize: number) => { onPagingChange({ pageIndex: isPagingReset ? 1 : pageIndex, pageSize, }); }; // 改变页码 const changePageIndex = (pageIndex: number) => onPagingChange({ pageIndex, pageSize, }); // 渲染分页状态信息 const stateElement = (() => { if (stateTextVisible === false) { return null; } return (
{typeof stateText === "undefined" ? t.paginationRecordCount(recordCount) : stateText}
); })(); // 当前页码大于总页,可选重置 useEffect( () => { if ( pageCountChangingResetType !== "unset" && recordCount > 0 && pageIndex > pageCount ) { onPagingChange({ pageIndex: pageCountChangingResetType === "first" ? 1 : pageCount, pageSize, }); } }, // eslint-disable-next-line react-hooks/exhaustive-deps [pageIndex, pageCount, recordCount] ); // 操作区元素 let operationElements: JSX.Element[] = []; // 页码输入 if (pageIndexVisible !== false) { operationElements = [ , ]; } // 页码跳转 if (jumpVisible !== false) { operationElements = [ 1 ? t.paginationPrevPage : t.paginationAtFirst} onClick={() => changePageIndex(pageIndex - 1)} classPrefix={classPrefix} />, ...operationElements, = pageCount} title={ pageIndex < pageCount ? t.paginationNextPage : t.paginationAtLast } onClick={() => changePageIndex(pageIndex + 1)} classPrefix={classPrefix} />, ]; } // 页头页尾跳转 if (endJumpVisible !== false) { operationElements = [ 1 ? t.paginationToFirstPage : t.paginationAtFirst} onClick={() => changePageIndex(1)} classPrefix={classPrefix} />, ...operationElements, = pageCount} title={ pageIndex < pageCount ? t.paginationToLastPage : t.paginationAtLast } onClick={() => changePageIndex(pageCount)} classPrefix={classPrefix} />, ]; } // 页长选择 if (pageSizeVisible !== false) { operationElements = [ setInputValue(evt.target.value)} onBlur={() => { const parsedPageIndex = parseInt(inputValue, 10); if ( parsedPageIndex !== pageIndex && parsedPageIndex >= 1 && parsedPageIndex <= pageCount ) { onChange(parsedPageIndex); } setInputValue(null); }} onKeyDown={evt => { // enter to confirm if (evt.key === KeyMap.Enter) { evt.preventDefault(); const parsedPageIndex = parseInt(inputValue, 10); if ( parsedPageIndex !== pageIndex && parsedPageIndex >= 1 && parsedPageIndex <= pageCount ) { onChange(parsedPageIndex); } setInputValue(null); } // up/down key else if (evt.key === KeyMap.Up || evt.key === KeyMap.Down) { let nextPageValue = parseInt(inputValue, 10); if (Number.isNaN(nextPageValue)) { nextPageValue = pageIndex; } if (evt.key === KeyMap.Up) { nextPageValue = Math.max(1, nextPageValue + 1); } else if (evt.key === KeyMap.Down) { nextPageValue = Math.min(pageCount, nextPageValue - 1); } setInputValue(String(nextPageValue)); } }} /> {t.paginationPageCount(pageCount)} ); } PageIndexInput.displayName = "PageIndexInput";