# 分页 Pagination > 列表底下一排页码,一页一页翻,页数多时中间用「…」省略。 分类:导航 [全部组件和流程](https://www.dachuiai.com/llms.txt) · [导航选型规则](https://www.dachuiai.com/guides/navigation.md) ## 给 AI:用户把这个组件发给了你 1. 先看用户的项目:框架、页面类型、现在的风格、手机还是电脑为主。 2. 对照下面的「适合 / 不适合」判断合不合适。不合适就直接说,并从[导航选型规则](https://www.dachuiai.com/guides/navigation.md)或[全部组件](https://www.dachuiai.com/llms.txt)里另挑一个。 3. 合适就按「装进项目」装好,示例里的文字和图片换成用户自己的。 4. 告诉用户用了什么、放在哪个文件、以后想改快慢、颜色、大小改哪个参数。 ## 什么时候用 - 适合:要对比、要回头找的列表:商品、搜索结果、后台表格。 - 不适合:随便刷着看的内容流(用无限滚动或加载更多);不到两页。 - 适合的网站:电商、后台、内容站、SaaS - 放在:列表 - 手机上:好用:页码按钮不小于 40px,页数多时只留上一页、当前页、下一页。 - 性能代价:低 - 常搭配:[布局动画 Layout Animation](https://www.dachuiai.com/c/layout-animation.md)、[流光 Shimmer](https://www.dachuiai.com/c/shimmer.md) ## 装进项目 - 写法:React 18 以上 + TypeScript + Tailwind CSS v4,一个文件就能用,不引用别的组件。 - 依赖:`npm i lucide-react` - 文件:原样存成 `pagination.tsx`(比如 `src/components/pagination.tsx`)。能跑命令就下载[原文](https://www.dachuiai.com/code/pagination.tsx),比手抄准:`curl -fsSL -o src/components/pagination.tsx https://www.dachuiai.com/code/pagination.tsx`(Windows 写 `curl.exe`)。下载完看一眼第一行是 `import`,不是网页。 - 导出:`pageList`、`Pagination` 是可以直接用的部分;最后的 `export default` 是演示示例,只作参考。 - 图片:示例用了本站的 [/tex/s5.jpg](https://www.dachuiai.com/tex/s5.jpg)、[/tex/s6.jpg](https://www.dachuiai.com/tex/s6.jpg)、[/tex/s3.jpg](https://www.dachuiai.com/tex/s3.jpg)、[/tex/s2.jpg](https://www.dachuiai.com/tex/s2.jpg)、[/tex/s1.jpg](https://www.dachuiai.com/tex/s1.jpg)、[/tex/s4.jpg](https://www.dachuiai.com/tex/s4.jpg)。换成用户自己的图;只想先看效果,可以从本站同样的路径下载,放进项目的 public 目录。 - 注意:page 是当前页,total 是总页数,onChange 翻页;pageList(page, total) 算出该显示哪些页码,可以单独用。翻页后把列表滚回顶部。 - 保留代码里 `prefers-reduced-motion` 的处理:用户开了「减弱动态效果」时内容照样完整显示。 - Next.js(有 app 文件夹):文件第一行加 `'use client';`。 - 用 JavaScript 不用 TypeScript:Vite 和 Next.js 都能直接用 .tsx 文件;也可以删掉类型标注,改名 .jsx。 - 没有 Tailwind:先装 Tailwind CSS v4(Vite 项目 `npm i tailwindcss @tailwindcss/vite`,vite 配置的 plugins 里加 `tailwindcss()`,入口引入的那个 CSS 文件(一般是 `src/index.css`)第一行写 `@import "tailwindcss";`),或者把类名改写成项目用的样式。 - 已经装了 Tailwind v3:别为了一个组件升级。类名大多通用,少数 v4 写法要换,比如焦点框 `outline-2` 在 v3 里要写成 `outline outline-2`。 - 不是 React(Vue、Svelte、小程序、纯 HTML):照着代码的做法改写,时长、曲线、参数保持一样。Wix、有赞这类建站平台装不进代码,告诉用户去平台自带的动效设置里找。 ## 参数 **pageList** | 参数 | 默认值 | 作用 | | --- | --- | --- | | `page` | | 当前第几页 | | `total` | | 一共几页 | **Pagination** | 参数 | 默认值 | 作用 | | --- | --- | --- | | `page` | | 当前第几页 | | `total` | | 一共几页 | | `onChange` | | 切换时调用,参数是新选中的那一项 | ## 你可以说 > 搜索结果底部加 Pagination 分页:上一页、页码、下一页,页数多时中间用省略号。 ## 完整代码 ```tsx import {useState} from 'react'; import {Backpack, Bed, ChevronLeft, ChevronRight, Flame, Lamp, Tent, Thermometer} from 'lucide-react'; /* --------------------------------------------------------------- * Pagination 分页 * 底下一排页码,一页一页翻。要对比、要回头找的列表(商品、搜索结果、表格)用它。 * 页数多时中间用"…"省略:始终显示第一页、最后一页和当前页前后各一页。 * ------------------------------------------------------------- */ export function pageList(page: number, total: number): (number | '…')[] { if (total <= 7) return Array.from({length: total}, (_, i) => i + 1); const set = new Set([1, total, page - 1, page, page + 1].filter((p) => p >= 1 && p <= total)); const arr = [...set].sort((a, b) => a - b); return arr.flatMap((p, i) => (i && p - arr[i - 1] > 1 ? ['…' as const, p] : [p])); } export function Pagination({page, total, onChange}: {page: number; total: number; onChange: (p: number) => void}) { const btn = 'grid h-10 min-w-10 place-items-center rounded-xl px-2 text-sm font-semibold tabular-nums transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-600'; return ( ); } /* ---------------- 示例:商品搜索结果 ---------------- */ const BASE = [['轻量双人帐篷', 899, '/tex/s5.jpg', Tent], ['徒步背包 40L', 459, '/tex/s6.jpg', Backpack], ['羽绒睡袋', 699, '/tex/s3.jpg', Bed], ['卡式炉', 239, '/tex/s2.jpg', Flame], ['露营灯', 159, '/tex/s1.jpg', Lamp], ['保温壶', 129, '/tex/s4.jpg', Thermometer]] as const; const MODEL = ['', ' Pro', ' Lite', ' 2026', ' Max', ' Air', ' Plus', ' Mini']; const PER = 6, TOTAL = 9; const item = (n: number) => { const b = BASE[n % 6]; return {name: b[0] + MODEL[Math.floor(n / 6) % MODEL.length], price: b[1] + Math.floor(n / 6) * 20, img: b[2], icon: b[3]}; }; export default function PaginationDemo() { const [page, setPage] = useState(1); return (