docs: add cbz chapter-scoped reading design spec
This commit is contained in:
@@ -0,0 +1,73 @@
|
|||||||
|
# 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.ts` helper 表驱动单测:锁/连读 × 预读 0–3 × 首章/末章/单章扁平包 × 边界页;
|
||||||
|
断言 mountEnd/scrollEnd 不越过滚动锁、预读不超过 count。
|
||||||
|
- 现有 `virt` 用例保持绿;`npm run check` 绿。
|
||||||
|
- 真实浏览器点验:锁章滚不到下章、开连读可滑过、预读下切章无白屏、扁平包无章 UI。
|
||||||
|
|
||||||
|
## 文档 / Docs
|
||||||
|
|
||||||
|
- `docs/CHANGELOG_web.md` 新增条目(英中各一行),不重复进 `docs/CHANGELOG.md`。
|
||||||
|
|
||||||
|
## 不做 / Non-goals
|
||||||
|
|
||||||
|
- 后端章节结构改动、章内页号重映射、PDF/EPUB/TXT 阅读器改动、横翻 RTL 模式、
|
||||||
|
长按拖拽越章「窥视」下一章。
|
||||||
Reference in New Issue
Block a user