File size: 5,036 Bytes
4167172
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 面试指南:微信公众号 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。