JavaScript如何为以[[开头、]]结尾的匹配文本设置背景颜色
实现方案
新手做这个功能最容易踩的坑就是直接粗暴重写整个容器的innerHTML,很容易把原有的事件绑定、页面结构搞坏,正确的做法是只针对纯文本节点做精准处理,给匹配到的[[xxx]]内容套上带自定义样式的标签就行。
实现步骤
- 提前定义高亮标签的样式,把想要的自定义背景色写进去
- 递归遍历容器内的所有纯文本节点,跳过其他类型的元素节点,避免破坏原有结构
- 用非贪婪全局正则精准匹配文本里被
[[、]]包裹的内容 - 拆分原文本片段,把匹配到的内容替换成带高亮类名的
<span>,保留所有未匹配的普通文本内容
可直接复用的代码
自定义高亮样式
.highlight-mark { /* 这里可以随便改你想要的背景色 */ background-color: #ffeb3b; padding: 0 3px; border-radius: 2px; }
功能逻辑代码
// 获取你放这段文本的div容器 const textContainer = document.querySelector('div'); // 递归遍历所有文本节点的工具函数 function traverseTextNodes(node, handleCallback) { // 遇到纯文本节点就直接走处理逻辑 if (node.nodeType === Node.TEXT_NODE) { handleCallback(node); return; } // 继续遍历子节点 node.childNodes.forEach(childNode => traverseTextNodes(childNode, handleCallback)); } // 匹配[[xxx]]的正则,非贪婪+全局匹配 const markPattern = /\[\[(.+?)\]\]/g; traverseTextNodes(textContainer, (textNode) => { const originalContent = textNode.textContent; markPattern.lastIndex = 0; // 没匹配到内容就直接跳过 if (!markPattern.test(originalContent)) return; // 用文档片段存处理好的内容,减少DOM操作次数 const contentFragment = document.createDocumentFragment(); let lastCutPos = 0; let matchResult; while ((matchResult = markPattern.exec(originalContent)) !== null) { // 把匹配位置之前的普通文本塞进去 if (matchResult.index > lastCutPos) { contentFragment.appendChild( document.createTextNode(originalContent.slice(lastCutPos, matchResult.index)) ); } // 创建高亮的span节点 const highlightEl = document.createElement('span'); highlightEl.className = 'highlight-mark'; highlightEl.textContent = matchResult[1]; contentFragment.appendChild(highlightEl); lastCutPos = matchResult.index + matchResult[0].length; } // 把最后剩下的普通文本塞进去 if (lastCutPos < originalContent.length) { contentFragment.appendChild( document.createTextNode(originalContent.slice(lastCutPos)) ); } // 用处理好的片段替换原来的纯文本节点 textNode.parentNode.replaceChild(contentFragment, textNode); });
之前实现失败的常见原因
- 用了贪婪匹配的正则:比如写成
/\[\[(.*)\]\]/g,会把第一个[[到最后一个]]中间的所有内容都当成匹配项,多个标记的时候就会串内容 - 直接操作整个容器的
innerHTML:虽然代码短,但会重绘容器里所有的DOM节点,之前给子元素绑定的click等事件会全部失效,遇到容器里有其他嵌套标签的时候还可能破坏页面结构 - 全局正则没重置
lastIndex:带g标记的正则会记忆上次匹配结束的位置,连续调用判断逻辑的时候会出现位置偏移,明明页面里有匹配内容却识别不到
你要是想改背景色,直接改CSS里的background-color值就行,不用动JS逻辑。
内容的提问来源于stack exchange,提问作者ali davoodi
相关产品推荐
相关产品推荐

