Skip to content

Pagination 分页 ​

一排页码加上一页 / 下一页。pt-pagination 是导航容器,里面每一项是一个 pt-pagination-item: 页码、上一页、下一页或省略号。

基础用法

共 10 页、当前第 5 页:当前页 ± 1 加首末页,断开处放省略号。项没有 href 时是按钮,点击发 ptSelect,detail 带着它的 page。

<pt-pagination>
  <pt-pagination-item kind="previous" page="4"></pt-pagination-item>
  <pt-pagination-item page="1"></pt-pagination-item>
  <pt-pagination-item kind="ellipsis"></pt-pagination-item>
  <pt-pagination-item page="4"></pt-pagination-item>
  <pt-pagination-item page="5" active></pt-pagination-item>
  <pt-pagination-item page="6"></pt-pagination-item>
  <pt-pagination-item kind="ellipsis"></pt-pagination-item>
  <pt-pagination-item page="10"></pt-pagination-item>
  <pt-pagination-item kind="next" page="6"></pt-pagination-item>
</pt-pagination>
链接

给了 href 就渲染成普通链接:服务端分页、可以在新标签页打开,点击照常跳转,不发 ptSelect。首页时上一页 disabled。

<pt-pagination>
  <pt-pagination-item kind="previous" disabled></pt-pagination-item>
  <pt-pagination-item page="1" href="?page=1" active></pt-pagination-item>
  <pt-pagination-item page="2" href="?page=2"></pt-pagination-item>
  <pt-pagination-item page="3" href="?page=3"></pt-pagination-item>
  <pt-pagination-item kind="next" href="?page=2"></pt-pagination-item>
</pt-pagination>

当前页归使用方 ​

分页不内置页码计算,也不持有当前页。当前页是你的状态:由你决定渲染哪些项、哪一项 active、 首末页时把上一页 / 下一页 disabled。每一项都写上它指向的 page(上一页 / 下一页也写), 点击时 ptSelect 的 detail 是 { kind, page },在 pt-pagination 上统一监听、直接把 detail.page 设成当前页即可。

常见排法是「首页 + 当前页 ± 1 + 末页,断开处放省略号」:

ts
function pageItems(current: number, total: number) {
  const pages = [...new Set([1, current - 1, current, current + 1, total])]
    .filter(n => n >= 1 && n <= total)
    .sort((a, b) => a - b);
  const items: ({ kind: 'page'; page: number } | { kind: 'ellipsis' })[] = [];
  pages.forEach((page, i) => {
    if (i > 0 && page - pages[i - 1] > 1) items.push({ kind: 'ellipsis' });
    items.push({ kind: 'page', page });
  });
  return items;
}
tsx
<PtPagination onPtSelect={event => setCurrent(event.detail.page!)}>
  <PtPaginationItem kind="previous" page={current - 1} disabled={current === 1} />
  {pageItems(current, total).map((item, i) =>
    item.kind === 'ellipsis' ? (
      <PtPaginationItem key={`e${i}`} kind="ellipsis" />
    ) : (
      <PtPaginationItem key={item.page} page={item.page} active={item.page === current} />
    )
  )}
  <PtPaginationItem kind="next" page={current + 1} disabled={current === total} />
</PtPagination>

按钮还是链接 ​

  • 不给 href:项渲染成 <button>,点击(或聚焦后按 Enter / Space)发 ptSelect。客户端分页用这种。
  • 给了 href:项渲染成 <a href>,点击照常跳转、不发 ptSelect,可以在新标签页打开。 服务端分页用这种。单页应用想拦下跳转自己路由时,在项上监听 click 并 preventDefault()。

disabled 的项一律渲染成禁用的按钮(即使给了 href),不可点、不发事件。

内容与文案 ​

项不接收子节点,内容全部由属性决定:页码写在 page 上;上一页 / 下一页的可见文字缺省是「上一页」「下一页」, 用 label 覆盖;省略号是固定的图标。内置文案走 locale 注册表(pagination.*),按元素的 lang 或 setLocale() 切换。

样式 ​

两个都是光 DOM 元素(没有 Shadow DOM),样式在全局样式表 ptengine-ui.css 里,所以一定要引这份样式表。 选择器全部包在 :where() 里,特异性只剩宿主标签,业务写一个类名就能盖过:

css
/* 写在项上:颜色、字号由项继承给里面的按钮 */
.my-page {
  color: var(--brand);
}
/* 写在里面的链接 / 按钮上:尺寸、圆角、底色、描边 */
.my-page > a,
.my-page > button {
  border-radius: 999px;
}

页码是 32×32 的方钮,上一页 / 下一页同高、按文字撑宽;普通项是透明底,当前页是带描边的次要按钮、文字走强调档。 触屏(pointer: coarse)下命中区扩到 44px,项与项的间距同时拉到 12px,相邻两项扩出的命中区不重叠。 从右往左(dir="rtl")时顺序与箭头方向一起翻转。

服务端渲染 ​

React(Next.js)与 Vue(Nuxt)下服务端输出的是空的 <pt-pagination-item> 标签(尺寸由全局样式表占住), 链接和按钮在元素 upgrade 之后才渲染出来,hydration 不报 mismatch。 依赖分页链接做搜索引擎抓取时,另在页面 <head> 里输出 <link rel="prev"> / <link rel="next">。

无障碍 ​

  • pt-pagination 是 role="navigation" 地标,名称取 label(缺省「分页」);一页有多组分页时给每组起不同的名字。
  • 页码项的读屏名是「第 N 页」,当前页带 aria-current="page";给页码项写 label 覆盖的是读屏名。
  • 省略号不可聚焦,图标对读屏隐藏,读屏念「更多页」。
  • 禁用的上一页 / 下一页是原生禁用按钮,带 aria-disabled="true"。

API ​

属性

属性Attribute类型默认值说明
labellabelstring | undefined—导航地标的读屏名称,缺省「分页」(`pagination.label`)。一页里有多组分页时给每组起不同的名字

事件

事件detail 类型说明
ptSelectPtPaginationSelectDetail某个没有 `href` 的项被点击,detail 为 `{ kind, page }`,`event.target` 是那一项。 这是 `pt-pagination-item` 发出、冒泡上来的事件,本元素**自己不发**;声明在这里只为让 React / Vue / Angular 包装层生成绑定(`onPtSelect` / `@pt-select` / `(ptSelect)`),可以在分页上统一监听,不必写在每一项上。 静态类型的限制:Stencil 生成的 `PtPaginationCustomEvent` 把 `target` 标成本元素,运行时却是那一项。

pt-pagination-item ​

属性

属性Attribute类型默认值说明
activeactivebooleanfalse当前页:`aria-current="page"`,样式换成带描边的次要按钮、文字走强调档
disableddisabledbooleanfalse禁用:首页的「上一页」、末页的「下一页」。渲染成禁用的按钮(即使给了 `href`),不可点、不发事件
hrefhrefstring | undefined—链接地址。给了渲染成 `<a>`(点了照常跳转、不发 `ptSelect`),没给渲染成按钮
kindkind"ellipsis" | "next" | "page" | "previous"'page'项的种类:页码、上一页、下一页、省略号
labellabelstring | undefined—文案覆盖。上一页 / 下一页:可见文字,缺省「上一页」「下一页」(`pagination.previous` / `pagination.next`); 页码:读屏名称,缺省「第 N 页」(`pagination.page`);省略号:读屏文字,缺省「更多页」(`pagination.more`)
pagepagenumber | undefined—页码。`page` 项显示它;上一页 / 下一页上写它表示「点了去第几页」,随 `ptSelect` 带出

事件

事件detail 类型说明
ptSelectPtPaginationSelectDetail没有 `href` 的项被点击时触发(Enter / Space 同样),detail 为 `{ kind, page }`。禁用项与省略号不发。 冒泡:`pt-pagination` 声明了同名事件,可以在分页上统一监听(框架包装层里同样能绑)。

Apache-2.0 协议开源