Files
endorphin-tabularium-docs/content/docs/pretext/06-chapter.md
T
codex-bot 2b3b3a1ae4
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 5m47s
Expand document collections with Pretext tutorial and simplify library navigation
2026-10-28 13:42:51 +08:00

2.3 KiB

第六章:为什么只求高度比拿到每行文字便宜

6.1 计算结果越详细,需要的工作越多

假设一个段落有 50 行。高度只需要一个行数;返回每行文字则还要确定范围、切字符串、拼接内容并创建结果对象。这些临时对象最终还需要垃圾回收。

因此选择 API 时应先问:调用者实际要什么?

需求 准备方式 布局 API
高度、行数 prepare() layout()
行数、最宽行 prepare() measureLineStats()
每行范围与宽度 prepare() walkLineRanges()
每行文字 prepareWithSegments() layoutWithLines()
逐行取文字,可按需停止 prepareWithSegments() layoutNextLine()

普通 prepare() 的最终 handle 不保留分段字符串;准备过程中仍会使用文字,不能因此说它完全没有字符串处理。

6.2 范围与文字分开生成

一行可以先表示为:

从第几个 segment 的第几个字素开始
到第几个 segment 的第几个字素结束
这一行有多宽

这是 range。需要显示那一行时,再把 range 变成实际字符串,这一步叫 materialize,即生成具体内容。

walkLineRanges() 不生成行字符串,但公共回调接收的 range 及其游标仍然会分配对象。它比“每行完整文字”做得少,也不应被描述成零分配。

line-text.ts还用 WeakMap 按 handle 缓存所需分段的字素结束位置。只有行边界切进一个分段内部、确实需要定位字素时,才会补上相关数据。

6.3 流式逐行适合什么情境

如果只显示前三行摘要,逐行 API 可以在取到所需行数时停止;如果每行可用宽度不同,也可以逐次传入不同宽度。

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 条消息各有多高,是否需要为每条创建所有行字符串?不需要。