Expand document collections with Pretext tutorial and simplify library navigation
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 5m47s

This commit is contained in:
2026-10-28 13:42:51 +08:00
parent 1f3ab5a7ee
commit 2b3b3a1ae4
28 changed files with 1174 additions and 761 deletions
+52
View File
@@ -0,0 +1,52 @@
# 第六章:为什么只求高度比拿到每行文字便宜
### 6.1 计算结果越详细,需要的工作越多
假设一个段落有 50 行。高度只需要一个行数;返回每行文字则还要确定范围、切字符串、拼接内容并创建结果对象。这些临时对象最终还需要垃圾回收。
因此选择 API 时应先问:调用者实际要什么?
| 需求 | 准备方式 | 布局 API |
| --- | --- | --- |
| 高度、行数 | `prepare()` | `layout()` |
| 行数、最宽行 | `prepare()` | `measureLineStats()` |
| 每行范围与宽度 | `prepare()` | `walkLineRanges()` |
| 每行文字 | `prepareWithSegments()` | `layoutWithLines()` |
| 逐行取文字,可按需停止 | `prepareWithSegments()` | `layoutNextLine()` |
普通 `prepare()` 的最终 handle 不保留分段字符串;准备过程中仍会使用文字,不能因此说它完全没有字符串处理。
### 6.2 范围与文字分开生成
一行可以先表示为:
```text
从第几个 segment 的第几个字素开始
到第几个 segment 的第几个字素结束
这一行有多宽
```
这是 range。需要显示那一行时,再把 range 变成实际字符串,这一步叫 materialize,即生成具体内容。
`walkLineRanges()` 不生成行字符串,但公共回调接收的 range 及其游标仍然会分配对象。它比“每行完整文字”做得少,也不应被描述成零分配。
[`line-text.ts`](https://github.com/chenglou/pretext/blob/0d102a5cd933611e86a7e60bda7b4baa5995c6b0/src/line-text.ts)还用 WeakMap 按 handle 缓存所需分段的字素结束位置。只有行边界切进一个分段内部、确实需要定位字素时,才会补上相关数据。
### 6.3 流式逐行适合什么情境
如果只显示前三行摘要,逐行 API 可以在取到所需行数时停止;如果每行可用宽度不同,也可以逐次传入不同宽度。
```js
let cursor
for (let i = 0; i < 3; i++) {
const line = layoutNextLine(preparedWithSegments, 320, cursor)
if (!line) break
console.log(line.text)
cursor = line.end
}
```
这个片段假设已经导入 `layoutNextLine` 并准备好 `preparedWithSegments`。它演示逐行读取,不包含省略号处理。高度用途直接选 `layout()` 会更合适。
本章检查:虚拟列表只想知道 10,000 条消息各有多高,是否需要为每条创建所有行字符串?不需要。