不能靠 innerHTML.replace() 批量高亮多选内容,因其会撕开HTML标签、忽略大小写、不转义正则元字符、不保关键词顺序,导致嵌套错乱或XSS;必须用TreeWalker遍历纯文本节点,按长度降序匹配并双重转义关键词,再用replaceChild安全替换。

不能靠 innerHTML.replace() 批量高亮多选内容——它会撕开 HTML 标签、忽略大小写差异、不处理正则元字符,且无法保证关键词顺序,导致嵌套错乱或 XSS。
为什么直接 replace 多个关键词会出错
比如同时高亮 JavaScript 和 Script,若按数组原始顺序执行 replace(),短词先匹配,可能产出 JavaScript 这类断裂结构。浏览器虽自动“修复”为两个独立 mark,但语义已丢失,CSS 无法统一控制边距或背景渐变。
更严重的是:用户输入 [a-z] 会崩正则;输入 <script>alert(1)</script> 会触发 XSS;原文含 React 时,replace() 把标签当纯文本撕开,DOM 解析失败。
- 必须对每个关键词做双重转义:
keyword.replace(/[&"'`=/]/g, c => `${c.charCodeAt(0)};`)(HTML 实体) +.replace(/[.*+?^${}()|[]]/g, '\$&')(正则元字符) - 必须按关键词长度降序排序,确保长词优先匹配
- 必须只操作纯文本节点,跳过所有 HTML 元素节点
用 TreeWalker 遍历文本节点再替换
核心是避开 innerHTML,只处理 node.nodeType === 3 的文本节点:
const walker = document.createTreeWalker(
container,
NodeFilter.SHOW_TEXT,
{ acceptNode: node => node.textContent.trim() ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT }
);
let node;
while (node = walker.nextNode()) {
const text = node.textContent;
const replaced = highlightWords(text, keywords); // 使用安全的高亮函数
if (replaced !== text) {
const mark = document.createElement('mark');
mark.innerHTML = replaced; // 注意:此处 replaced 已是安全 HTML 字符串
node.parentNode.replaceChild(mark, node);
}
}
关键点:
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
-
document.createTreeWalker()确保只遍历真实文本,不碰、等容器 - 每次只替换一个节点,避免跨节点匹配(如关键词横跨两个
) - 替换后用
replaceChild()而非insertAdjacentHTML(),防止插入位置错乱
高亮函数要支持词边界和大小写安全
别用 /keyword/gi 简单粗暴匹配——它会把 hello-world 中的 hello 也高亮。正确做法是加 词边界,并用捕获组保留原大小写:
const highlightWords = (text, words) => {
const escaped = words
.filter(w => w && typeof w === 'string')
.map(w => w.replace(/[.*+?^${}()|[]]/g, '\$&'));
if (!escaped.length) return text;
const regex = new RegExp(`\b(${escaped.join('|')})\b`, 'gi');
return text.replace(regex, '<mark>$</mark>');
};
注意:$& 表示完整匹配内容,能保留原始大小写; 在中文场景下效果有限,如需支持中英文混合,得改用 (? + (?=$|\s) 边界逻辑。
真正麻烦的不是写代码,而是判断哪些文本节点该进高亮流程——比如 里的代码字面量、 的 value、被 contenteditable="false" 锁住的区域,都得跳过。漏掉一个,就可能让 mark 套在 <script></script> 标签里,白忙活还埋雷。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










