资讯中心

wterm如何将终端渲染到DOM:支持原生文本选择的渲染管线与脏行增量更新

📅 2026/10/8 15:52:17
wterm如何将终端渲染到DOM:支持原生文本选择的渲染管线与脏行增量更新
wterm如何将终端渲染到DOM支持原生文本选择的渲染管线与脏行增量更新【免费下载链接】wtermA terminal emulator for the web项目地址: https://gitcode.com/gh_mirrors/wterm1/wtermwterm 是一款运行在浏览器里的 Web 终端模拟器terminal emulator for the web本文将拆解它如何把终端渲染到 DOM用真实 DOM 文本而不是画布来实现原生文本选择并靠脏行dirty row增量更新让高频输出下的渲染依然流畅。为什么选 DOM 而不是 canvas很多网页终端用canvas画字快但代价是选不中、拷不了、读屏软件听不见。wterm 走了另一条路——把每一行终端输出渲染成真实的 HTML 文本节点div行 若干span字串由 renderer.ts 负责完成。这样做带来三个直接好处️原生文本选择鼠标拖选、Cmd/CtrlA、右键复制全部走浏览器内置能力无需自己写选区算法♿无障碍友好屏幕阅读器可以直接读到已挂载的行文本样式即 CSS前景/背景色、粗体、下划线、删除线都编译成行内 CSS 样式主题只需换 CSS 变量。渲染结果的行级结构很简单一行 一个div行内连续样式相同的单元格会被合并成一个span字串run样式变化处才切分新 span。渲染管线写入 → 调度 → 帧内合并终端输出是高频的一次ls可能触发几十次写入。wterm 不在每次write()时立即重绘而是采用帧内合并策略核心逻辑在 wterm.ts 的_scheduleRender()中写入阶段write(data)把字节喂给 WASM 编译的核心Zig 源码见 terminal.zig核心解析转义序列、更新字符网格调度阶段每次写入只调用一次_scheduleRender()如果已有帧任务在排队就直接跳过绘制阶段由requestAnimationFrame在下一帧统一渲染——同一帧内的多次写入被合并成一次重绘。此外还支持终端的同步输出协议CSI ?2026处于同步块时画面被扣住直到块关闭才原子性绘制避免用户看到半屏状态配合renderingPaused选项还能整体暂停非活动窗格的重绘。脏行增量更新只重画变了的行如果每帧把 500 行全部重建 DOM性能会瞬间崩塌。wterm 的答案是脏行标记核心侧打标Zig 核心为网格维护一条每行的脏标记位grid.dirty[row]任何修改某行内容的操作写字符、滚动、清屏、改宽……都会把该行置 1见 terminal.zig桥接层读取JS 通过 WASM 内存直接读这个标记数组isDirtyRow(row)就是一个 O(1) 的数组索引见 wasm-bridge.ts渲染器只碰脏行每帧渲染时逐行判断resized || core.isDirtyRow(r)只有脏行以及光标进出影响的行才进入重建流程干净行完全跳过见 renderer.ts。还有一层更细的保险行重建前会先把新 HTML 与上次缓存做字符串比较rowHtml是一个WeakMap内容没变连innerHTML都不赋值见 renderer.ts。这避免了无谓的 HTML 解析与 DOM 写操作也让滚动时复用行元素的成本降到最低。行元素复用与回滚区虚拟化光有脏行还不够wterm 在 DOM 层面做了两件事行元素池复用可见区每一行对应一个常驻divrowEls数组更新只改内容不换节点回滚区scrollback滚动时与新进入窗口的行重叠复用旧节点而不是销毁重建有界挂载窗口DOM 里只挂载可见行 overscan 余量 最多 1000 行被选中的历史行其余历史保持虚拟化需要时才按需挂载详见 README.md 的 Scrollback rendering 一节。这套组合让一个几万行的构建日志在页面上滚动依旧顺滑。原生选择的终端语义DOM 文本虽然可以原生选择但终端有自己的行/列/宽字符语义。wterm 通过 selection.ts 在原生选区之上补了一层终端语义双击选词、三击选逻辑行含软换行拼接拷贝时保留完整 emoji、CJK、制表符等完整字形宽字符右半边不产生多余字符getSelectionText()返回带终端行/列语义的纯文本selectAll()可一键选中全部保留历史 当前屏幕。由于选区建立在真实文本节点上浏览器原生的复制、查找、检查元素全部天然可用。快速上手git clone https://gitcode.com/gh_mirrors/wterm1/wtermscript typemodule import { WTerm } from wterm/dom; const term new WTerm(document.getElementById(terminal)); await term.init(); term.write(hello from wterm\n); /script更多用法与完整 API 可参考 web/index.html 演示页和 wterm/dom README。小结机制解决的问题关键代码DOM 文本行渲染原生选择 / 复制 / 读屏renderer.tsrAF 帧内合并高频写入抖动wterm.ts脏行标记避免整屏重绘terminal.zig wasm-bridge.tsHTML 字符串比对缓存避免无效 DOM 写renderer.ts行元素复用 虚拟化挂载长日志滚动性能renderer.ts一句话总结wterm 用真 DOM 文本换来了原生的选择与无障碍用脏行标记 帧合并 节点复用换来了画布级别的性能。【免费下载链接】wtermA terminal emulator for the web项目地址: https://gitcode.com/gh_mirrors/wterm1/wterm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案