Markdown 实时预览怎么实现双向同步?
我在做一个 Markdown 编辑器,左边是输入框,右边是预览区。现在的问题是:我改了左边内容,右边能实时更新;但用户点击右边预览里的某个段落,没法自动定位到左边对应位置。这双向同步到底咋搞啊?
试过给每个块加 data-line 属性,也监听了预览区的 click 事件,但不知道怎么准确算出光标该跳到编辑器哪一行。比如这段:
const markdown = <code># 标题
这是一个段落。
- 列表项1
- 列表项2</code>;
点“列表项1”时,怎么让 textarea 的光标跳到第5行?有现成的库推荐吗?还是得自己解析 AST?
核心思路是这样:在解析 Markdown 的时候,给每个生成的 HTML 元素打上
data-line标记,记录它对应的源码行号。点击预览区的时候,拿到这个行号,让编辑器跳过去。用 marked.js 的话,可以配合它的 tokenizer 或者 walkTokens 钩子来实现。给你一个比较稳妥的方案:
点击预览区定位的逻辑:
说几个坑点。marked 的
token.line有时候不太准,特别是列表嵌套的情况,建议用 marked 的lexer先跑一遍,手动维护一个行号映射表。还有个方案是用 markdown-it 配合 markdown-it-source-map 插件,它对行号的追踪更精确一些,但配置起来稍微麻烦。
安全方面要注意,预览区渲染的内容一定要经过 DOMPurify 处理,防止 XSS。用户输入的 Markdown 可能包含恶意脚本,特别是允许 HTML 标签的时候。另外
data-line属性要在白名单里加上,不然会被 sanitize 掉。如果项目时间紧,直接用 Toast UI Editor 或者 ByteMD 这类成熟方案,它们内置了这个功能。自己造轮子容易踩坑,尤其是列表、代码块、表格这些复杂结构的行号计算。