Vue应用中实现DOM搜索词高亮及滚动至首个结果的方法
Vue 搜索词汇高亮实现方案
核心思路
要实现高亮不能直接替换元素的textContent(会破坏原有DOM结构),需递归遍历文本节点,将匹配词汇用带样式的<span>包裹;同时每次搜索前要清除之前的高亮,避免重复嵌套。
修改后的完整代码
// 清除已有高亮的方法 clearHighlights() { const highlights = document.querySelectorAll('.search-highlight'); highlights.forEach(highlight => { const parent = highlight.parentNode; parent.replaceChild(document.createTextNode(highlight.textContent), highlight); parent.normalize(); // 合并相邻文本节点 }); } search() { // 先清除历史高亮 this.clearHighlights(); const searchTerm = this.searchTerm; // 假设searchTerm是Vue data中定义的搜索关键词 if (!searchTerm.trim()) return; // 空关键词直接终止 // 修正选择器:body后加空格,选中body下所有符合条件的子元素 const elements = document.querySelectorAll('body *:not(script):not(style):not(title):not(.search-highlight)'); let firstMatch = null; // 递归处理文本节点的函数 const highlightText = (element) => { // 跳过已高亮节点,避免重复处理 if (element.classList?.contains('search-highlight')) return; for (let i = 0; i < element.childNodes.length; i++) { const node = element.childNodes[i]; // 仅处理文本节点 if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent; const regex = new RegExp(`(${searchTerm})`, 'gi'); // g全局匹配,i不区分大小写 if (regex.test(text)) { // 将文本分割为匹配/非匹配片段 const fragments = text.split(regex); const fragment = document.createDocumentFragment(); fragments.forEach((part, index) => { if (index % 2 === 1) { // 奇数位为匹配的关键词 const span = document.createElement('span'); span.className = 'search-highlight'; span.textContent = part; // 记录第一个匹配项用于滚动 if (!firstMatch) firstMatch = span; fragment.appendChild(span); } else { fragment.appendChild(document.createTextNode(part)); } }); // 替换原文本节点 element.replaceChild(fragment, node); } } else { // 非文本节点,递归处理子节点 highlightText(node); } } }; // 遍历所有目标元素执行高亮 elements.forEach(element => highlightText(element)); // 滚动到第一个匹配项 if (firstMatch) { firstMatch.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }
高亮样式(添加到Vue的<style>中)
.search-highlight { background-color: #ffeb3b; padding: 2px 4px; border-radius: 2px; font-weight: bold; }
注意事项
searchTerm需在Vue的data中定义,示例:data() { return { searchTerm: '' } }- 递归处理时跳过已高亮节点,避免
<span>嵌套重复 - 使用
document.createDocumentFragment减少DOM操作次数,提升性能 - 正则修饰符
gi可按需调整,比如去掉i则区分大小写
内容的提问来源于stack exchange,提问作者gabogabans
相关产品推荐
相关产品推荐

