3.2 KiB
3.2 KiB
目标效果
- 自动显隐 Markdown 标记:光标不在当前行/当前元素时,自动隐藏
#、*、**、>、```等语法标记,只显示渲染后的文本;光标移入时恢复显示以便编辑。 - 代码块所见即所得:代码块(Fenced Code Block)显示为灰色背景的卡片块,优化字体和间距,不再只是裸露的文本。
- 柔和样式优化:调整行高、字号、颜色、段落间距,使其视觉上更接近渲染后的文档(Typora 风格)。
技术方案
1. 核心逻辑重构:从 StateField 转向 ViewPlugin
目前的 liveMarkdownDecorations.js 基于正则匹配行,无法精准处理嵌套语法(如加粗内的斜体)和光标交互。将改用 ViewPlugin 结合 syntaxTree(语法树):
- 语法树解析:利用
@codemirror/language提供的syntaxTree遍历文档节点,精准识别HeaderMark(标题#)、EmphasisMark(*)、CodeMark()、FencedCode`(代码块)等节点。 - 光标感知:在
ViewPlugin的update钩子中监听docChanged和selectionSet。 - 动态装饰:
- 隐藏逻辑:如果节点的范围 不包含 当前光标选区,则对该节点的语法标记部分应用
Decoration.replace({})(完全隐藏)或Decoration.mark({ class: 'cm-md-hidden' })。 - 代码块逻辑:识别
FencedCode节点,对整个范围应用Decoration.line({ class: 'cm-md-fenced-code' })添加背景色;对首尾的CodeMark(```)在非聚焦时进行隐藏或弱化处理。
- 隐藏逻辑:如果节点的范围 不包含 当前光标选区,则对该节点的语法标记部分应用
2. 样式实现细节
- 隐藏类 (
.cm-md-hidden):设置为display: none或font-size: 0。 - 代码块样式 (
.cm-md-fenced-code):- 背景色:
var(--app-background)或微调的灰色。 - 圆角与内边距:让代码块看起来像一个独立的容器。
- 字体:使用等宽字体 (
monospace)。
- 背景色:
- 柔和排版:
- 增加
line-height(如 1.8)。 - 增加段落间距 (
margin-bottom效果)。 - 调整标题 (
Header) 的font-weight和border-bottom,使其更像预览模式。
- 增加
实施步骤
- 废弃旧逻辑:清空或重写
src/codemirror/liveMarkdownDecorations.js。 - 实现
ViewPlugin:- 引入
syntaxTree。 - 编写遍历逻辑,识别 Markdown 节点。
- 实现光标包含判断逻辑。
- 生成
Decoration.replace(隐藏) 和Decoration.line(样式)。
- 引入
- 完善 CSS:在
LivePreviewEditor.vue中补充对应的 CSS 规则(.cm-md-hidden,.cm-md-header,.cm-md-fenced-code等)。 - 验证:测试标题、加粗、代码块在光标移入/移出时的显隐效果。
预期节点类型 (基于 @lezer/markdown)
ATXHeading: 包含HeaderMark(#) 和内容。Emphasis/StrongEmphasis: 包含EmphasisMark(*, _)。FencedCode: 包含CodeMark(```),CodeInfo(语言),CodeText(内容)。Blockquote: 包含QuoteMark(>)。
风险点
- 性能:频繁遍历语法树可能在长文档中导致卡顿。需要利用
RangeSetBuilder高效构建 Decoration,并尽量复用。 - 光标边界:光标恰好在标记边缘时的显隐判定需要精细调整(通常光标接触即显示)。