# markdown-preview **Repository Path**: muzil/markdown-preview ## Basic Information - **Project Name**: markdown-preview - **Description**: 基于 Vue 3 的在线 Markdown 编辑器,支持实时分屏预览、代码高亮、Mermaid 流程图、暗色主题、自动保存与多格式导出。 - **Primary Language**: JavaScript - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-18 - **Last Updated**: 2026-06-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Markdown Preview > 基于 Vue 3 的在线 Markdown 编辑器,支持实时分屏预览、代码高亮、Mermaid 流程图、暗色主题、自动保存与多格式导出。 ## 特性 - **Monaco Editor** — 专业级 Markdown 编辑体验(语法高亮、代码补全、撤销/重做) - **实时分屏预览** — 左编辑右预览,50/50 固定布局 - **代码语法高亮** — highlight.js 支持 JS、TS、Python、Go、Rust 等数十种语言 - **Mermaid 流程图** — 在代码块中使用 `` ```mermaid `` 渲染流程图、时序图、甘特图 - **暗色/亮色主题** — CSS 自定义属性 + Monaco 主题 + Mermaid 主题三路同步 - **localStorage 自动保存** — 500ms 防抖写入,刷新恢复,多标签页同步 - **CJK 感知字数统计** — 中英文混合文本准确统计 - **三种导出** — `.md` 下载 / 自包含 HTML / 浏览器打印 PDF - **XSS 防护** — markdown-it `html: false` + DOMPurify 双重净化 ## 技术栈 | 分类 | 技术 | |------|------| | 框架 | Vue 3 + TypeScript | | 构建 | Vite 8 | | 编辑器 | Monaco Editor (ESM 动态导入) | | 解析 | markdown-it + GFM 插件 | | 高亮 | highlight.js | | 图表 | Mermaid.js | | 净化 | DOMPurify | | 测试 | Vitest | | 样式 | CSS 自定义属性(无 CSS 框架) | ## 快速开始 ### 环境要求 - Node.js 20+ - pnpm ### 安装 ```bash pnpm install ``` ### 开发 ```bash pnpm dev ``` 浏览器打开 `http://localhost:5173` ### 生产构建 ```bash pnpm build ``` 产物输出到 `dist/` 目录 ### 预览构建产物 ```bash pnpm preview ``` ### 测试 ```bash # 单元测试 pnpm test # 监听模式 pnpm test:watch ``` ## 项目结构 ``` src/ ├── App.vue # 根组件:布局集成 + 状态管理 ├── main.ts # 应用入口 + CSS 导入 ├── components/ │ ├── SplitPane.vue # 50/50 固定分屏布局 │ ├── MarkdownPreview.vue # Markdown 渲染预览区(含 Mermaid 内联渲染) │ ├── StatusBar.vue # 字数统计 + 保存状态 │ └── ThemeToggle.vue # 主题切换按钮 ├── composables/ │ ├── useCodeEditor.ts # Monaco 编辑器封装(动态加载) │ ├── useMarkdown.ts # markdown-it 解析流水线 │ ├── useStorage.ts # localStorage 自动保存 │ ├── useTheme.ts # 主题管理 + 三路同步 │ ├── useWordCount.ts # CJK 感知字数统计 │ ├── useExportMd.ts # .md 文件导出 │ └── useExportHtml.ts # 自包含 HTML 导出 ├── plugins/ │ └── mermaidPlugin.ts # markdown-it Mermaid fence 插件 ├── utils/ │ ├── cjk.ts # 中英文混合字数统计 │ ├── debounce.ts # 防抖函数 │ ├── sanitize.ts # DOMPurify 安全净化 │ └── welcome.ts # 首次打开示例文档 ├── styles/ │ ├── variables.css # 主题 CSS 自定义属性 │ ├── preview.css # 预览区排版样式 │ └── print.css # PDF 打印样式 ├── types/ │ ├── index.ts # 全局类型定义 │ ├── markdown-it-task-lists.d.ts # 第三方插件类型声明 │ └── monaco-editor-api.d.ts # Monaco ESM API 类型声明 └── __tests__/ └── useMarkdown.test.ts # Markdown 解析单元测试 (11 用例) ``` ## 关键设计决策 | 决策 | 选择 | 排除 | |------|------|------| | Monaco 集成 | 原生 `monaco-editor` + Vite `?worker` | vite-plugin-monaco-editor-esm | | Vue 封装 | 自定义 composable (`useCodeEditor`) | monaco-editor-vue3 / @guolao/vue-monaco-editor | | Monaco 加载 | 动态 `import()` 异步加载 | 同步 import(阻塞页面渲染) | | Monaco 入口 | `esm/vs/editor/editor.api`(轻量) | 全量 barrel import(含所有语言服务) | | Markdown 解析 | markdown-it + GFM 插件 | marked / remark | | XSS 防护 | `html: false` + DOMPurify 双层 | 单一防护 | | Mermaid 渲染 | `mermaid.run()` 内联渲染 | 独立 Vue 组件 / `startOnLoad: true` | | PDF 导出 | `window.print()` + `@media print` | jsPDF / html2pdf.js | | 主题系统 | CSS 自定义属性(`:root` / `[data-theme]`) | Tailwind / UnoCSS / CSS Modules | | 状态管理 | Composables + 响应式引用 | Pinia / Vuex | ## 导出功能说明 ### .md 导出 - 直接下载编辑器中的 Markdown 源文本 - MIME 类型: `text/markdown` ### HTML 导出 - 自包含 HTML 文件,内嵌 CSS 样式 - Mermaid 图表以占位符形式导出(不含运行时 JS) - 无需外部依赖,可直接在浏览器中打开 ### PDF 导出 - 点击"打印 / PDF"按钮调用 `window.print()` - 在浏览器打印对话框中选择"另存为 PDF" - `@media print` 规则隐藏编辑器面板,仅保留预览内容 - 自动处理分页、代码块防断页、Mermaid SVG 保留 ## 主题系统 主题通过 CSS 自定义属性实现三路同步: ``` CSS [data-theme] ─┐ ├→ 一致的用户体验 Monaco vs/vs-dark ─┘ Mermaid default/dark ─┘ ``` 切换主题时: 1. `` 的 `data-theme` 属性更新,CSS 变量自动切换 2. Monaco 编辑器通过 `monaco.editor.setTheme()` 切换 3. MarkdownPreview 监听 theme prop 变化,调用 `mermaid.run()` 重新渲染 ## 安全 - **XSS 防护**: markdown-it 配置 `html: false` 阻止原始 HTML 渲染 - **DOMPurify**: 对 markdown-it 输出进行二次净化 - **SVG 安全**: DOMPurify 白名单包含必要的 SVG 元素(``、``、`` 等)供 Mermaid 渲染 ## License MIT