# 面试指南:微信公众号 Markdown 编辑器 (WeChat Markdown Editor) > 本文档旨在辅助你理解项目核心架构与技术难点,以便在面试中流利作答。 ## 1. 项目概述 (Project Overview) **一句话介绍**: 这是一个基于 Web 的 Markdown 编辑器,专注于解决微信公众号排版繁琐、代码展示不友好以及外链限制等痛点。它能够将 Markdown 实时渲染为适配微信公众号样式的 HTML,支持一键复制发布。 **核心价值**: - **效率提升**:让技术博主专注于写作,而非排版。 - **样式定制**:通过 CSS 变量实现多主题切换(如 Notion 风格),满足不同审美。 - **平台适配**:针对微信环境的特殊限制(如外链、代码块)做了专门处理。 ## 2. 技术架构 (Technical Architecture) 虽然项目看似简单,但其架构设计体现了**轻量化**和**关注点分离**的思想。 - **后端 (Backend)**: Python Flask - **角色**:主要作为静态资源服务器(Static File Server)。 - **优势**:轻量、部署简单(配合 Docker/Gunicorn),易于后续扩展(如增加账号系统或云端存储)。 - **前端 (Frontend)**: Vue 3 + Tailwind CSS - **Vue 3**:利用 Composition API (`setup`, `ref`, `computed`) 管理编辑器状态(源码、预览 HTML、主题设置)。 - **Tailwind CSS**:快速构建现代化的 UI 界面,提高开发效率。 - **核心引擎**: Markdown-it + Highlight.js - **渲染**:在浏览器端实时将 Markdown 解析为 HTML AST,再渲染为 DOM。 - **高亮**:自动检测代码语言并应用高亮样式。 ## 3. 核心难点与解决方案 (Key Challenges & Solutions) 面试中如果被问到“项目中遇到的最大困难是什么”,可以从以下几点回答: ### 难点 1:微信公众号的样式兼容性 (Style Adaptation) **问题**:微信公众号后台编辑器过滤掉了许多外部 CSS,且对某些 HTML 标签(如 `h1`, `blockquote`)的默认样式支持不一致。 **解决方案**: - **内联样式模拟**:虽然没有使用内联样式库(如 juice),但我通过精心设计的 CSS 选择器(`#preview-content h1` 等)确保复制到剪贴板的内容带有所需的样式信息。微信编辑器在粘贴富文本时会保留大部分计算后的样式。 - **自定义 CSS 变量**:使用 `:root` 和 `data-theme` 属性实现主题切换。这样只需修改变量值,无需重写大量 CSS 规则。 ### 难点 2:外链处理 (External Links) **问题**:微信公众号文章除白名单外,不支持普通外部超链接,导致文章中的参考链接无法点击。 **解决方案**: - **自定义 Renderer**:利用 `markdown-it` 的插件机制,重写 `link_open` 和 `link_close` 规则。 - **脚注转换**:在渲染过程中,将所有外链收集到一个 `footnotes` 数组中。渲染结束后,在文章底部自动追加一个“引用链接”列表,并将正文中的链接转换为上标索引(如 `[1]`)。 ### 难点 3:富文本一键复制 (Rich Text Copy) **问题**:普通的 `navigator.clipboard.writeText` 只能复制纯文本,无法保留颜色和排版。 **解决方案**: - **Range API**: 创建一个 `Range` 对象选中预览区域的 DOM 节点。 - **Selection API**: 将 `Range` 添加到当前的 `Selection` 中。 - **execCommand**: 使用 `document.execCommand('copy')`(虽然标准标记为过时,但在处理“富文本复制”场景下,它仍然是兼容性最好、最可靠的方案)。 ### 难点 4:同步滚动 (Sync Scroll) **问题**:左侧 Markdown 源码和右侧渲染后的 HTML 高度不一致,如何实现精准的同步滚动? **解决方案**: - **百分比映射**:计算当前滚动条位置占总可滚动高度的百分比 (`scrollTop / (scrollHeight - clientHeight)`),并将此百分比应用到另一侧。 - **防抖动 (Debounce/Lock)**:为了防止“循环触发”滚动事件(左滚带动右,右滚又带动左),设置了一个 `isScrolling` 标志位,在滚动触发时锁定,滚动结束后(通过 `setTimeout`)释放。 ### 难点 5:中英文自动空格 (Pangu Spacing) **问题**:为了提升排版美感,中英文之间应该有空格(如 "Hello你好" -> "Hello 你好")。 **解决方案**: - **正则替换**:前端实现了一个轻量级的替换逻辑。 - `text.replace(/([\u4e00-\u9fa5])([a-zA-Z0-9])/g, '$1 $2')`:中文后跟英文/数字。 - `text.replace(/([a-zA-Z0-9])([\u4e00-\u9fa5])/g, '$1 $2')`:英文/数字后跟中文。 ## 4. 为什么做这个项目? - **自我驱动**:作为一个技术人员,我经常写技术博客。现有的工具要么收费,要么功能太复杂,我希望有一个**轻量、可控、隐私安全(纯本地渲染)**的工具。 - **技术实践**:我想通过这个项目深入理解前端的**文本处理**和**DOM 操作**,同时实践 Vue 3 的 Composition API。