## 目标效果 1. **自动显隐 Markdown 标记**:光标不在当前行/当前元素时,自动隐藏 `#`、`*`、`**`、`> `、` ``` ` 等语法标记,只显示渲染后的文本;光标移入时恢复显示以便编辑。 2. **代码块所见即所得**:代码块(Fenced Code Block)显示为灰色背景的卡片块,优化字体和间距,不再只是裸露的文本。 3. **柔和样式优化**:调整行高、字号、颜色、段落间距,使其视觉上更接近渲染后的文档(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`,使其更像预览模式。 ## 实施步骤 1. **废弃旧逻辑**:清空或重写 `src/codemirror/liveMarkdownDecorations.js`。 2. **实现 `ViewPlugin`**: - 引入 `syntaxTree`。 - 编写遍历逻辑,识别 Markdown 节点。 - 实现光标包含判断逻辑。 - 生成 `Decoration.replace` (隐藏) 和 `Decoration.line` (样式)。 3. **完善 CSS**:在 `LivePreviewEditor.vue` 中补充对应的 CSS 规则(`.cm-md-hidden`, `.cm-md-header`, `.cm-md-fenced-code` 等)。 4. **验证**:测试标题、加粗、代码块在光标移入/移出时的显隐效果。 ## 预期节点类型 (基于 @lezer/markdown) - `ATXHeading`: 包含 `HeaderMark` (#) 和内容。 - `Emphasis` / `StrongEmphasis`: 包含 `EmphasisMark` (*, _)。 - `FencedCode`: 包含 `CodeMark` (```), `CodeInfo` (语言), `CodeText` (内容)。 - `Blockquote`: 包含 `QuoteMark` (>)。 ## 风险点 - **性能**:频繁遍历语法树可能在长文档中导致卡顿。需要利用 `RangeSetBuilder` 高效构建 Decoration,并尽量复用。 - **光标边界**:光标恰好在标记边缘时的显隐判定需要精细调整(通常光标接触即显示)。