本文档描述了Joplin中的渲染管道,该管道负责将笔记内容从其存储格式(Markdown或HTML)转换为用户在笔记查看器中看到的视觉表示。该管道处理初始渲染和交互式更新,包括编辑器和查看器之间的同步滚动。
有关编辑器本身的信息,请参阅富文本编辑器和Markdown编辑器。有关跨平台编辑器组件,请参阅跨平台编辑器组件。
渲染管道将内容从笔记编辑器转换为最终显示的格式,同时在编辑器和查看器之间保持双向同步。它处理多种输入格式,应用样式,渲染特殊元素(如数学公式和图表),并同步编辑器和查看器窗格之间的滚动。
来源:packages/app-desktop/gui/NoteTextViewer.tsx1-249 packages/app-desktop/gui/note-viewer/index.html1-859
笔记查看器包含两个主要组件
NoteTextViewer 组件通过消息传递与 iframe 通信,实现双向数据流和事件处理。
来源:packages/app-desktop/gui/NoteTextViewer.tsx59-246 packages/app-desktop/gui/note-viewer/index.html41-46
NoteTextViewer 组件提供了一个包含以下关键方法的控制接口
setHtml(html, options):设置要显示 HTML 内容send(channel, arg0, arg1):向 iframe 发送消息focus():聚焦笔记查看器focusLine(lineNumber):聚焦查看器中的特定行hasFocus():检查查看器当前是否聚焦来源:packages/app-desktop/gui/NoteTextViewer.tsx27-34 packages/app-desktop/gui/NoteTextViewer.tsx72-158
渲染笔记时,会执行以下步骤
setHtml(html, options)来源:packages/app-desktop/gui/NoteTextViewer.tsx72-158 packages/app-desktop/gui/note-viewer/index.html441-482
渲染管道的一个关键方面是源映射系统,它向 HTML 元素添加属性以跟踪它们与源 markdown 行的关系。
在 markdown 到 HTML 的转换过程中,会将特殊属性添加到 HTML 元素中
class="maps-to-line":标记带有源行信息的元素source-line="n":源 markdown 中的起始行号source-line-end="m":源 markdown 中的结束行号这些属性可以实现编辑器和查看器位置之间的精确同步。
来源:packages/renderer/MdToHtml/rules/source_map.ts1-41
源映射系统支持以下 markdown 元素
| 元素类型 | 最大嵌套级别 |
|---|---|
| 段落 | 0 |
| 标题 | 0 |
| 引用块 | 0 |
| 表格 | 0 |
| 代码块 | 0 |
| 水平线 | 0 |
| HTML 块 | 0 |
| 列表项 | 99 |
| 数学块 | 0 |
来源:packages/renderer/MdToHtml/rules/source_map.ts7-18
渲染管道中最复杂的方面之一是编辑器和查看器之间的双向滚动同步。
滚动映射系统维护编辑器行号和查看器滚动位置之间的映射。这使得无论编辑器和查看器之间内容布局有何差异,都能实现同步滚动。
来源:packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.ts1-249 packages/app-desktop/gui/note-viewer/scrollmap.js1-123
滚动映射处理三种不同的坐标系统
转换函数在这些系统之间进行转换
translateScrollPercentE2L:将编辑器百分比转换为逻辑百分比translateScrollPercentL2E:将逻辑百分比转换为编辑器百分比translateL2V:将逻辑百分比转换为查看器百分比translateV2L:将查看器百分比转换为逻辑百分比来源:packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.ts206-243 packages/app-desktop/gui/note-viewer/scrollmap.js87-122
滚动映射在内容更改时创建,并在布局更改时刷新
scrollmap.create(lineCount):使用源总行数创建新的滚动映射scrollmap.refresh():使缓存的映射无效,强制重新计算scrollmap.get_():通过分析带有 maps-to-line 类的 DOM 元素来惰性构建映射来源:packages/app-desktop/gui/note-viewer/scrollmap.js13-80
渲染管道通过以下方式支持与插件集成
渲染笔记时,可以包含插件资产
setHtml 方法在选项中接受插件资产资产管理系统跟踪已添加的资产,避免重复,并在不再需要时删除资产。
来源:packages/app-desktop/gui/NoteTextViewer.tsx75-94 packages/app-desktop/gui/note-viewer/index.html158-228
插件可以通过消息系统与笔记查看器通信
webviewApi 对象提供了一个 postMessage 方法这使得插件无需直接 DOM 操作即可扩展查看器的功能。
来源:packages/app-desktop/gui/NoteTextViewer.tsx36-57 packages/app-desktop/gui/note-viewer/index.html55-79
Markdown 内容被转换为 HTML 以在笔记查看器中显示。在此转换过程中
来源:packages/renderer/MdToHtml/rules/source_map.ts1-41
@joplin/turndown 包将来自富文本编辑器的 HTML 转换为 markdown 格式。这允许在不丢失内容的情况下无缝切换编辑模式。
来源:packages/turndown/package.json1-54 packages/turndown-plugin-gfm/package.json1-46
笔记查看器响应从编辑器发送的各种命令
| 命令 | 目的 |
|---|---|
setHtml | 更新显示的內容 |
scrollToHash | 滚动到指定的锚点 |
setPercentScroll | 滚动到指定位置 |
setMarkers | 高亮搜索词 |
focus | 聚焦查看器 |
focusLine | 聚焦特定行 |
查看器还会将事件发送回编辑器
percentScroll:用户在查看器中滚动时noteRenderComplete:内容完全渲染时contextMenu:用户在查看器中右键单击时来源: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts1-172 packages/app-desktop/gui/note-viewer/index.html81-136
渲染管道包含多种机制来处理边缘情况
来源: packages/app-desktop/gui/note-viewer/index.html266-367 packages/app-desktop/gui/note-viewer/index.html608-668
渲染管道处理将笔记从其存储格式转换为渲染显示,同时保持诸如同步滚动之类的交互式功能,这是一个复杂的过程。它通过以下方式实现:
理解此管道对于开发与笔记渲染交互的功能或实现自定义渲染扩展至关重要。