Skip to content

fix(reader): 修正章节内页码换算,去掉不存在的首尾 padding 假设 (#745) - #751

Open
chy5301 wants to merge 1 commit into
codedogQBY:mainfrom
chy5301:fix/chapter-page-numbering
Open

fix(reader): 修正章节内页码换算,去掉不存在的首尾 padding 假设 (#745)#751
chy5301 wants to merge 1 commit into
codedogQBY:mainfrom
chy5301:fix/chapter-page-numbering

Conversation

@chy5301

@chy5301 chy5301 commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Closes #745

问题

章节内页码(右上角 当前页/总页数)换算有误,两端(桌面 / 移动)表现一致:

  1. 章节开头翻两页,页码才 +1(第 1、2 页都显示 1
  2. 章节末尾两页都显示满值
  3. 显示的章节总页数比实际少 2
  4. 只有 1~2 屏的短章节完全不显示页码,回退成全书百分比

根因

renderer.page 是 0 基索引,renderer.pages 就是章节真实页数(paginator.jsget page() / get pages()),paginator 不会在章节首尾插入 padding 页 —— expand() 里的 this.#element.style.padding = '0' 是清 CSS box padding 以精确计算列宽,与分页无关。

但两端都按「首尾各有一页 padding」换算,把 current 压平在 [1, pages-2]

renderer.page 修复前显示
0 1
1 1
P-2 P-2
P-1 P-2

首尾各被 clamp 压平一次,正好对应上面四个现象。

改动

两端统一改为 current = page + 1total = pages,保留 clamp 以防边界滚动时的瞬时越界:

current: Math.min(Math.max(rendererPage + 1, 1), rendererPages),
total: rendererPages,

门槛 rendererPages > 2 一并放宽为 > 0 —— 它原本只是为了配合减 2 不越界而设,去掉减 2 后就没有存在理由了。短章节因此能正常显示 1/1,不再回退成百分比。

顺带修正的统计问题

两端的阅读量统计都用 detail.page.current 判断是否翻页(ReaderView.tsxsamePage / movedForwardWithinSection,移动端 ReaderScreen.tsx 同)。此前章首两页 current 相同,会被判成停在同一页而漏计字符。本次一并修正。

这不是历史包袱

追了一下,-2 不是为绕开某个问题而付的临时代价,而是一开始就写错的假设:

  • 7d5732f3(2026-04-06,"添加对 Expo Go 的限制提示和数据库写入重试机制")在移动端首次引入 page 字段,直接带 -2
  • 74c76d92(2026-04-18,"添加字符阅读统计功能")把这段逐字复制到桌面端

两个 commit 的 message、diff、相邻代码都没有任何关于「空白页 / padding / 越界」的说明;paginator.jsget page() / get pages() 自 vendor 进仓库起从未改过,历史上也不存在过 padding 页。所以没有东西依赖这个 -2

测试

新增 packages/app-expo/src/screens/reader/chapter-page-numbering-contract.test.ts,沿用仓库已有的 contract test 写法(同 justified-text-contract.test.ts):断言两端换算一致、不再出现 rendererPages - 2,并校验构建产物与模板同步。

已验证:

  • pnpm --filter @readany/app-expo test 全绿(7 文件 17 测试),并反向验证过——还原改动后新测试会失败
  • pnpm --filter app exec tsc --noEmit 通过
  • biome 对改动文件无新增问题(既有 error 数改动前后一致)

尚未做真机手测,麻烦 review 时留意实际观感(尤其滚动模式与短章节)。

关于 reader.html 产物 diff

本 PR 的产物 diff 中约 94 行不是本次逻辑改动,而是补上 72274af8(sync: rebase page-margin work onto latest main)遗漏的产物同步 —— 那是个 merge commit,更新了 reader.template.htmlpaginator.js,却没有同步 reader.html。在干净的 main 上什么都不改、只跑一次 pnpm run build:reader 就能复现这 94 行 diff。这意味着该次页边距修复目前在移动端实际未生效,本 PR 顺带把产物同步上了。

renderer.page 是 0 基索引,renderer.pages 就是章节真实页数,paginator
并不会在章节首尾插入 padding 页。但两端都按「首尾各有一页 padding」换算,
把 current 压平在 [1, pages-2] 区间,导致:章首第 1、2 页都显示 1,
章尾最后两页都显示满值,显示的总页数比实际少 2。

改为 current = page + 1、total = pages,保留 clamp 以防边界滚动时的
瞬时越界。门槛 rendererPages > 2 一并放宽为 > 0——它原本只是为了配合
减 2 不越界而设,现在 1~2 屏的短章节也能正常显示页码,不再回退成全书
百分比。

补充:桌面端与移动端的阅读量统计都用 detail.page.current 判断是否翻页,
此前章首两页 current 相同会被判成同一页而漏计,一并修正。

同步重建 assets/reader/reader.html。
@chy5301

chy5301 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

补充一份桌面端真机验证(Windows / Tauri,同一本 EPUB,第十章「飞跃研究所」,renderer.pages = 7)。用 Playwright 连 WebView2 的 CDP 驱动真实应用,逐页发真实按键事件,同时读取 renderer.page / renderer.pages 真值与 UI 显示值:

renderer.page (0-based) renderer.pages 修复前 UI 修复后 UI
0 7 1 / 5 1 / 7
1 7 1 / 5 2 / 7
2 7 2 / 5 3 / 7
3 7 3 / 5 4 / 7
4 7 4 / 5 5 / 7
5 7 5 / 5 6 / 7
6 7 5 / 5 7 / 7

修复后 7 页全部与真值一致。

另外补充一个 #745 里没写到的后果:修复前倒数第二页就已经显示「5 / 5」,即 UI 谎称本章已读完,实际后面还有一整页。总页数恒少 2,首尾各有一次「翻了一页页码不动」。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 章节内页码换算错误:章节首尾各少/多算一页,翻两页页码才 +1

1 participant