必须只操作纯文本节点以避免破坏富文本DOM结构,使用TreeWalker遍历text节点并用mark元素替换关键词;高亮前需先提取textContent,再回填innerHTML,注意缓存表单状态;Markdown代码块需正则提取并转义后生成pre/code结构。

富文本里直接套 <mark></mark> 会撕开 DOM
富文本(比如从 CMS、Markdown 解析器或用户输入框来的 HTML)通常含 <p></p>、<strong></strong>、<code> 等标签。如果粗暴地用 innerHTML.replace() 把关键词包进 <mark></mark>,很容易把 <code>console.log() 变成 <code>console.<mark>log</mark>()
这会导致:DOM 解析失败、浏览器自动修正但语义断裂、<mark></mark> 被吞掉或错位。
- 必须跳过所有元素节点,只操作纯文本节点(
node.nodeType === 3) - 用
document.createTreeWalker(element, NodeFilter.SHOW_TEXT)安全遍历 - 对每个文本节点的
textContent做匹配和替换,不碰innerHTML - 匹配后用
document.createElement('mark')创建新节点,再调用node.parentNode.replaceChild(mark, node)
highlightWords() 函数处理富文本前要先提取纯文本
像 highlightWords(text, words) 这类字符串级函数,只适合处理已剥离 HTML 的纯文本。如果你传入的是带标签的富文本字符串,它会把 、<code>> 当普通字符匹配,也可能把正则元字符(如 .、?、[)当语法解析,直接报错。
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
- 先用
element.textContent或new DOMParser().parseFromString(html, 'text/html').body.textContent提取干净文本 - 再喂给高亮函数,得到带
<mark></mark>的 HTML 字符串 - 最后用
element.innerHTML = highlightedHTML回填 —— 注意:这会清空原有事件监听器和表单状态 - 更稳妥的做法是:在提取文本前缓存关键节点引用(如
<input>的value),回填后再恢复
动态插入的 Markdown 代码块需先转成 <pre class="brush:php;toolbar:false;"></code> 结构</H3><p>流式响应(如 SSE 或 GPT API)返回的 Markdown 代码块是 <pre class="brush:php;toolbar:false;">
console.log(1)</pre> 这种纯文本格式,<code>highlight.js 的 hljs.highlightAll() 根本不识别——它只扫描已渲染的 <pre class="brush:php;toolbar:false;"><code class="js"></code> 元素。</p><ul><li>必须用正则提取 <code>```(\w+)?\n([\s\S]*?)\n```</code>,并做 HTML 实体转义(<code>&</code> → <code>&</code>,<code><</code> → <code><</code> 等)</li><li>生成标准结构:<code><pre class="brush:php;toolbar:false;"><code class="js">console.log(1)</pre>
hljs.highlightElement(codeEl)(推荐单个元素高亮,避免重复扫描)insertAdjacentHTML 完成后再遍历新 <code> 元素逐个高亮
<mark></mark> 在 WebView 和邮件客户端里默认失效
WebView(尤其是 Android WebView 旧版本)和 Outlook 邮件客户端完全忽略 <mark></mark> 的 UA 样式,表现为透明背景、文字不可见,甚至整段消失。
立即学习“前端免费学习笔记(深入)”;
- 必须显式声明
background-color和color,不能依赖浏览器默认值 - 内联样式最保险:
<mark style="background-color:#ffeb3b;color:#212121;padding:0 2px;">关键词</mark> - 若用 CSS 类,务必加前缀(如
highlight-search),避免被第三方 UI 库重置 - 深色模式下要手动适配:
@media (prefers-color-scheme: dark) { .highlight-search { background-color: #4caf50; } }
富文本高亮真正的难点不在“怎么标”,而在“标在哪”和“标完还剩什么”——文本节点边界、DOM 层级嵌套、客户端兼容性、XSS 防御,每一步漏掉一个,上线后都可能表现为内容错乱、样式丢失或安全漏洞。


















