diff --git a/.ua/index.json b/.ua/index.json index eaa23e6..0762224 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-26T15:11:40.469Z", + "generatedAt": "2026-10-26T15:13:43.474Z", "repoRoot": ".", "packages": [ { @@ -1729,9 +1729,9 @@ }, { "n": "total", - "t": "number", + "t": "number | Signal", "r": 1, - "d": "总条数" + "d": "总条数;传信号则总量变化时自动重算页数(并把越界页码钳回并回调 onChange)" }, { "n": "simple", @@ -1777,7 +1777,8 @@ "与 dataTable 联动:把同一个 page 信号传给 dataTable 的 page 参数,两处翻页自动同步", "键盘可达:全部是原生 button,Tab 聚焦后 Enter / Space 触发", "pageSizes 传候选数组即出现「N 条/页」切换器,切换后自动回第 1 页;onPageSizeChange 拿新条数重算数据", - "空间紧的地方传 simple:页码区换成「3 / 5」文字 + 两个箭头(文字带 aria-live,翻页会被读屏播报);数据少到只有一页时再传 hideOnSinglePage,整块自动消失而不是留个灰掉的 1" + "空间紧的地方传 simple:页码区换成「3 / 5」文字 + 两个箭头(文字带 aria-live,翻页会被读屏播报);数据少到只有一页时再传 hideOnSinglePage,整块自动消失而不是留个灰掉的 1", + "总量会变(筛选 / 删除后)就把 total 传信号:页码越界时组件自动钳到最后一页并回调 onChange,父级 state 不会停在空页" ] }, { diff --git a/apps/demo/main.ts b/apps/demo/main.ts index 9329cde..c6c34ef 100644 --- a/apps/demo/main.ts +++ b/apps/demo/main.ts @@ -1363,6 +1363,19 @@ const content = h( pagination({ page: simplePage, pageSize: 20, total: 9, hideOnSinglePage: true }), // 单页:整块不渲染 h('span', { class: 'out' }, '单页隐藏:上面那块 9 条 / 每页 20 已自动消失'), ), + (() => { + // 总量走信号:点「筛到 25 条」后页码从 14 自动钳到 3,父级 state 同步收到回调 + const liveTotal = signal(137); + const livePage = signal(14); + return h( + 'div', + { class: 'row' }, + pagination({ page: livePage, pageSize: 10, total: liveTotal, onChange: (p) => livePage(p) }), + button({ label: '总量 137 条', variant: 'ghost', onClick: () => liveTotal(137) }), + button({ label: '筛到 25 条', variant: 'ghost', onClick: () => liveTotal(25) }), + h('span', { class: 'out' }, () => `第 ${livePage()} 页 / 共 ${Math.max(1, Math.ceil(liveTotal() / 10))} 页`), + ); + })(), ), section( 'sec-menu', diff --git a/llms-full.txt b/llms-full.txt index 4295cf6..08d92fe 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-26T15:11:40.469Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-26T15:13:43.474Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -870,7 +870,7 @@ space({ size: 'lg' }, button({ label: '保存' }), button({ label: '取消', var - page(必填):Signal —— 当前页码信号,双向绑定:外部赋值自动翻页,点击页码写回信号 - pageSize(必填):number —— 每页条数 -- total(必填):number —— 总条数 +- total(必填):number | Signal —— 总条数;传信号则总量变化时自动重算页数(并把越界页码钳回并回调 onChange) - simple(默认 false):boolean —— 极简模式:只留上一页 / 下一页与「当前 / 总页」文字,适合表格工具栏等窄位 - hideOnSinglePage(默认 false):boolean —— 只有一页时整个分页器隐藏(不占布局位) - onChange(回调):(page: number) => void —— 翻页回调 @@ -893,6 +893,7 @@ const page = signal(1); pagination({ page, pageSize: 3, total: 24, onChange: (p) 5. 键盘可达:全部是原生 button,Tab 聚焦后 Enter / Space 触发 6. pageSizes 传候选数组即出现「N 条/页」切换器,切换后自动回第 1 页;onPageSizeChange 拿新条数重算数据 7. 空间紧的地方传 simple:页码区换成「3 / 5」文字 + 两个箭头(文字带 aria-live,翻页会被读屏播报);数据少到只有一页时再传 hideOnSinglePage,整块自动消失而不是留个灰掉的 1 +8. 总量会变(筛选 / 删除后)就把 total 传信号:页码越界时组件自动钳到最后一页并回调 onChange,父级 state 不会停在空页 现场演示:apps/docs/demo.html#sec-pagination diff --git a/packages/skin/ui/src/pagination.ts b/packages/skin/ui/src/pagination.ts index 3f1d3d6..5f5f516 100644 --- a/packages/skin/ui/src/pagination.ts +++ b/packages/skin/ui/src/pagination.ts @@ -1,4 +1,4 @@ -import { h, renderList, signal } from '@ui-arch/frame'; +import { effect, h, renderList, signal } from '@ui-arch/frame'; import type { PaginationProps } from './types.js'; import { select } from './select.js'; @@ -21,7 +21,8 @@ function pageSequence(page: number, totalPages: number): (number | null)[] { export function pagination(props: PaginationProps): HTMLElement { // —— 状态集中声明 —— const size = signal(props.pageSize); // 每页条数:可从 switcher 改动,故用信号持有 - const totalPages = () => Math.max(1, Math.ceil(props.total / size())); // 总页数随时可重算 + const readTotal = (): number => (typeof props.total === 'function' ? props.total() : props.total); // 数字 / 信号同一口径 + const totalPages = () => Math.max(1, Math.ceil(readTotal() / size())); // 总页数随时可重算 const pages = h('div', { class: 'ua-pagination-pages' }); // 页码区,随页码重绘 const tail = h('div', { class: 'ua-pagination-tail' }); // 附加区(条数切换 + 跳页),只创建一次 const go = (p: number) => { @@ -29,6 +30,15 @@ export function pagination(props: PaginationProps): HTMLElement { props.page(next); props.onChange?.(next); }; + // 总量变小(筛选 / 删除)后把越界页码写回父级:否则父级 state 停在旧页,显示与数据对不上 + effect(() => { + const max = totalPages(); + const cur = props.page(); + if (cur <= max && cur >= 1) return; // 卫语句:页码合法就不动手,避免无意义回调 + const fixed = Math.min(max, Math.max(1, cur)); + props.page(fixed); + props.onChange?.(fixed); + }); // —— 每页条数切换器:传了候选才渲染,切换即回第 1 页 —— if ((props.pageSizes ?? []).length > 1) { diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index f546e0e..efd4d59 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -369,7 +369,7 @@ export interface SkeletonProps { export interface PaginationProps { page: Signal; // 当前页码信号,双向绑定(外部赋值自动翻页) pageSize: number; // 每页条数 - total: number; // 总条数 + total: number | Signal; // 总条数;传信号则总量变化时自动重算页数(并钳制越界页码) jumpable?: boolean; // 开启后在末尾显示跳页输入框(总页数 > 1 才出现) pageSizes?: number[]; // 每页条数候选(如 [10, 20, 50]);传了才渲染条数切换器 simple?: boolean; // 极简模式:只留上一页 / 下一页与「当前 / 总页」文字,适合工具栏窄位;缺省 false diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index 6ed8889..7cfb2b4 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -1600,9 +1600,9 @@ }, { "n": "total", - "t": "number", + "t": "number | Signal", "r": 1, - "d": "总条数" + "d": "总条数;传信号则总量变化时自动重算页数(并把越界页码钳回并回调 onChange)" }, { "n": "simple", @@ -1648,7 +1648,8 @@ "与 dataTable 联动:把同一个 page 信号传给 dataTable 的 page 参数,两处翻页自动同步", "键盘可达:全部是原生 button,Tab 聚焦后 Enter / Space 触发", "pageSizes 传候选数组即出现「N 条/页」切换器,切换后自动回第 1 页;onPageSizeChange 拿新条数重算数据", - "空间紧的地方传 simple:页码区换成「3 / 5」文字 + 两个箭头(文字带 aria-live,翻页会被读屏播报);数据少到只有一页时再传 hideOnSinglePage,整块自动消失而不是留个灰掉的 1" + "空间紧的地方传 simple:页码区换成「3 / 5」文字 + 两个箭头(文字带 aria-live,翻页会被读屏播报);数据少到只有一页时再传 hideOnSinglePage,整块自动消失而不是留个灰掉的 1", + "总量会变(筛选 / 删除后)就把 total 传信号:页码越界时组件自动钳到最后一页并回调 onChange,父级 state 不会停在空页" ] }, {