# 第九章:把它接进界面和虚拟列表 ### 9.1 一个完整的浏览器模块例子 先在你的前端项目中安装: ```sh npm install @chenglou/pretext ``` 下面是供 Vite 等支持 npm 模块导入的环境使用的 JavaScript 模块。直接打开一个 HTML 文件并不能解析这个包名。 ```js import { prepare, layout } from '@chenglou/pretext' const text = 'Hello 世界,今天一起读源码。'.repeat(8) const font = '16px "Helvetica Neue", "PingFang SC", Arial, sans-serif' const lineHeight = 24 document.documentElement.lang = 'zh-CN' await document.fonts.load(font, text) const prepared = prepare(text, font) const block = document.createElement('div') block.textContent = text Object.assign(block.style, { font, lineHeight: lineHeight + 'px', overflowWrap: 'break-word', wordBreak: 'normal', whiteSpace: 'normal', lineBreak: 'auto', letterSpacing: '0px', wordSpacing: '0px', fontKerning: 'auto', textWrap: 'wrap', hyphens: 'manual', textRendering: 'auto', boxSizing: 'content-box', padding: '0', border: '0', }) document.body.appendChild(block) function setContentWidth(width) { const predicted = layout(prepared, width, lineHeight) block.style.width = width + 'px' return predicted } const predicted = setContentWidth(320) console.log('预测高度:', predicted.height) console.log('实际高度:', block.getBoundingClientRect().height) // 模拟容器变宽:复用相同的 prepared。 setContentWidth(480) ``` 这个例子最后的 DOM 高度读取是开发期核对。生产中如果每次布局都再读一次 DOM,仍会承担那次读取可能触发的工作。示例也假设没有其他 CSS 规则覆盖这些值,所用字体在目标设备上可用;跨平台项目应配置自己的字体。 ### 9.2 让模型与显示使用相同输入 `layout(prepared, 320, 24)` 中的 320 是内容宽度。如果外框总宽 320px、左右各有 12px padding,再加边框,真正给文字使用的宽度就小于 320px。 可以由应用维护一个尺寸模型:先算出内容宽度,把同一个数同时传给 Pretext 和渲染层。这样可以减少“CSS 用一个值,JS 猜另一个值”的误差。 准备前等待具体文字所需字体加载很重要。只有 `document.fonts.ready` 不一定覆盖尚未使用、由 unicode-range 分片加载的字体;因此例子把 text 也传给 `document.fonts.load()`。 ### 9.3 虚拟列表从哪里获得收益 假设有 10,000 条消息,屏幕上只显示 20 条: ```text 每条消息保留 prepared → 按当前内容宽度求各条高度 → 累计高度,确定每条消息顶部的位置 → 按滚动位置找可见范围 → 只挂载可见消息与少量缓冲区 ``` Pretext 解决的是“没挂载的文字怎样求高度”。累计位置、查找可见范围、滚动锚定、图片高度、选择与无障碍行为,仍由应用或虚拟列表库负责。 窗口变宽时,每条消息通常仍需要重新布局。因此大量消息的整表 resize 成本不会凭空消失。准备与布局分离,让这次更新的单位成本更低。 ### 9.4 编辑与富文本如何处理 长文本编辑时,可以按段落保留 prepared,只重新准备被编辑影响的段落;有跨段结构变化时,应用还要更新相应块。 混合字体、提及标签和行内图片使用 `@chenglou/pretext/rich-inline`。这个版本把富文本作为一个段落分析,保留 item 与分段的映射,然后复用布局基础设施,而不是把每个 span 完全独立换行。 富文本还要考虑垂直尺寸:字体大小、上升部与下降部、行内盒子高度都可能影响真实行高。不要直接把所有富文本的行数乘一个固定值,当成任意 CSS 的精确高度。可继续读项目自己的 [Markdown 聊天案例说明](https://github.com/chenglou/pretext/blob/0d102a5cd933611e86a7e60bda7b4baa5995c6b0/pages/demos/markdown-chat.md)。 本章检查:Pretext 是否已经替你完成虚拟列表?没有,但它提供了此前很难在挂载前获得的文本几何信息。