4.7 KiB
4.7 KiB
CBZ 章节化连续阅读(锁章 + 预读)设计 / CBZ chapter-scoped continuous reading design
日期 2026-09-08。分支 feat/ui-redesign。状态:已获用户批准(会话内确认)。
目标 / Goal
漫画(CBZ)阅读以「章」为单位:一章内无论多少图都视为一段连续的整章内容, 默认不能靠上下滑动越过章界进入下一章(只能点「下一章」),可开「连读」让滑动贯穿章节。 去掉现有 连读/整页/适高 三档概念。锁章时预渲染(挂载+解码)其后 N 章(用户可配置,默认 2), 切章零白屏。 CBZ reading is chapter-scoped: images within a chapter flow continuously; by default scrolling cannot cross a chapter boundary (only the 下一章 button can); an optional 连读 mode lets scrolling flow into following chapters. The three-mode cycle (连读/整页/适高) is removed. The next N chapters (user-configurable, default 2) are pre-rendered while locked so chapter switches are instant.
决策记录 / Decisions
- 章节内显示 = 按容器宽度(≤720px)连续滚动、无 snap、无适高一屏一页。用户选定(方案 A)。
- 翻页手势/按键 = 章内翻一屏(
scrollBy ±vh),不再按图跳页。用户选定。 - 采用「按章节作用域渲染」(方案 A),否决:全书渲染+滚动钳制(手感生硬、浪费加载)、 一章一挂载(书签/进度/量高学习跨章迁移复杂、切章闪烁)。
- 预读实现为隐藏层挂载解码(不增加可滚动高度),不违反锁章语义。用户要求「可预渲染下两章、可配置」。
- 进度滑条/页码/书签/服务端进度均仍为全书页号,locator 形状
{page}不变,无后端/API 改动。 - 扁平包(chapters 为 null)= 整本一章:章按钮与连读开关隐藏,锁章/预读无意义,行为即纯连续滚动。
前端 / Frontend(全部改动在 frontend/src,纯前端)
状态与持久化
- 删除
PageMode/MODES/MODE_LABEL/useStoredMode及cbz-mode键;PageImg 去掉fitH分支; 滚动盒去掉snap-y snap-proximity。 localStorage("cbz-continuous"):连读开关,默认关(锁章)。localStorage("cbz-prefetch"):预读章数 0–3,默认 2。工具栏步进器按钮循环 0→1→2→3→0。
区间几何
- 当前章
ci由滚动位置(现cur所在页 → 章)推出,章起点chapters[ci].start。 PageHeights仍覆盖全书count页(复用现有量高/估高/applyShift补偿逻辑)。- 挂载上限
mountEnd:锁章 = 第ci+1+prefetch章起点(越界取 count);连读 = count。 - 滚动终点
scrollEnd:锁章 =ph.offset(章末) + 章末卡片高;连读 = 全书末尾。 - 超出
scrollEnd的预读页渲染进一个height:0; overflow:hidden的绝对定位隐藏层 (子页仍按ph.offset(i)定位、aria-hidden):blob 经fetchObjectUrl缓存、<img>挂载即解码, 但不参与滚动几何。切章后这些页落入可见区间即直接上屏。 - 纯计算抽为
lib/virt.ts导出 helper(如chapterRange(chapters, count, ci, continuous, prefetch)→{mountStart, mountEnd, scrollEndPage}),vitest 覆盖。
交互
- 点按左右侧区/←→/PageUp·Down:
scrollBy(±vh, smooth);锁章时滚动高度天然停在章末卡片。 - 点中间仍唤出工具栏(不变)。
- 章末卡片:锁章时本章末尾一屏「本章完 · 下一章 →」(最终章显示「全书完」),点卡片=切章。
- 切章入口(上一章/下一章按钮、目录行、书签 seek、章末卡片、滑条拖入他章区间):
设
ci并jump(page);滑条跨章视为显式定位,不算「滑动越界」。 - 恢复进度:由
initialLocator.page反推所在章后定位。 - 闲时「停滚 250ms 预取后 5 页」保留。
错误处理 / Errors
- 无新增失败面:页数接口、鉴权取图、失败重试(「本页加载失败」)均沿用。
cbz-prefetch值非法(手改 localStorage)→ 回退默认 2;cbz-continuous非"1"→ 关。
测试 / Tests
lib/virt.tshelper 表驱动单测:锁/连读 × 预读 0–3 × 首章/末章/单章扁平包 × 边界页; 断言 mountEnd/scrollEnd 不越过滚动锁、预读不超过 count。- 现有
virt用例保持绿;npm run check绿。 - 真实浏览器点验:锁章滚不到下章、开连读可滑过、预读下切章无白屏、扁平包无章 UI。
文档 / Docs
docs/CHANGELOG_web.md新增条目(英中各一行),不重复进docs/CHANGELOG.md。
不做 / Non-goals
- 后端章节结构改动、章内页号重映射、PDF/EPUB/TXT 阅读器改动、横翻 RTL 模式、 长按拖拽越章「窥视」下一章。