最省事的本地 html 差异生成方式是用 diff -u 结合 pygmentize 或 diff2html-cli;纯前端实时对比推荐 diff-match-patch,需转义输入并自定义 ins/del 样式。

用 diff 命令生成 HTML 差异片段最省事
本地有两版 HTML 笔记文件(比如 note_v1.html 和 note_v2.html),直接用命令行比对生成带高亮的 HTML 片段,比手写 JS 库快得多,也更可控。
- 先用
diff -u输出统一格式差异,再用pygmentize(需安装 Pygments)转成带 class 的 HTML:diff -u note_v1.html note_v2.html | pygmentize -l diff -f html -O full=false
- 若没装 Pygments,可用
diff2html-cli(Node.js):运行npx diff2html-cli -i stdin -F diff.html -- -u note_v1.html note_v2.html,输出含内联样式的完整 HTML 文件 - 注意:原始 HTML 中若有
<script></script>或<style></style>标签,diff会把它们当纯文本比对——这是对的,你本就不该在笔记 HTML 里嵌动态逻辑
纯前端用 diff-match-patch 做行级高亮
如果必须在浏览器里实时对比两个 HTML 字符串(比如编辑器预览区),diff-match-patch 是目前最轻、最稳的选择,它不解析 DOM,只处理字符串,避免 XSS 风险和解析错乱。
- 加载库:
<script src="https://unpkg.com/diff-match-patch@1.0.5/index.js"></script> - 调用时传入两个 HTML 字符串,用
dmp.diff_main()得到操作列表,再用dmp.diff_prettyHtml()生成带<ins></ins>/<del></del>的 HTML 片段 - 关键点:必须先对原始 HTML 做
encodeURIComponent级别转义(或用DOMPurify.sanitize()过滤),否则用户输入的<img onload="alert(1)">会被原样插入并执行 - 性能提示:超过 50KB 的 HTML 字符串会让
diff_main()明显卡顿,建议限制单次对比长度,或加 loading 提示
highlight.js 不适合 HTML 差异高亮
很多人第一反应是用 highlight.js 给 diff 输出上色,但它默认只认语言类型(如 language-diff),不理解 HTML 内容结构,会导致:
<div class="new"> 这种行被当成普通文本,class 名、引号、尖括号全乱色<li>无法区分「新增标签」和「新增文字内容」,<code><p>Hello</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6712" title="Wechat HTML Publisher"><img src="https://img.php.cn/upload/skill/000/000/081/179109368394970.jpg" alt="Wechat HTML Publisher" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill6712" title="Wechat HTML Publisher" class="overflowclass">Wechat HTML Publisher</a> <p class="overflowclass">直接上传HTML富文本到微信公众号草稿箱。支持完整的HTML格式,无需Markdown转换。</p> </div> <a rel="nofollow" href="/xiazai/skill6712" title="Wechat HTML Publisher" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>变成<p></p>绿、Hello绿、绿,失去语义- 如果你硬要塞进
<pre class="brush:php;toolbar:false;"><code class="diff"></code>,得自己先把 HTML 转义成 <code><div></code>,再让 highlight.js 渲染——多此一举,不如直接用 <code>diff-match-patch</code></pre> - 至少覆盖:去掉
text-decoration,改用背景色 + 边框,例如:ins { background-color: #d4edda; border-radius: 2px; }<br>del { background-color: #f8d7da; text-decoration: none; } - 如果对比的是代码块内的 HTML(比如 Markdown 渲染后的内容),还要防止
ins/del被父级pre或code的white-space截断——给ins, del加white-space: normal - 别依赖
!important,用足够具体的 CSS 选择器,比如.note-diff ins,避免污染全局
样式必须重写 ins 和 del 的默认行为
浏览器对 <ins></ins> 默认加下划线、<del></del> 加删除线,但笔记对比中你需要更克制的视觉反馈。
实际做笔记版本对比时,最易被忽略的是 HTML 字符串的预处理粒度:不是“整个文件丢进去”,而是按语义块(如每个 <h2></h2> 段落)分段 diff,否则一个标题改了,后面所有内容的行号全偏移,高亮就失去定位意义。










