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

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










