如何在不中断的情况下突出显示 html 内容字符串中的搜索文本

我正在寻找一些解决方案来帮助从具有突出显示功能的 html 字符串中搜索术语。我可以通过从字符串中删除 html 内容来做到这一点。但问题是我将无法看到带有突出显示的原始内容。我确实有以下功能,可以在没有 html 标记的情况下搜索和突出显示字符串。


private static updateFilterHTMLValue(value: string, filterText: string): string

{

    if (value == null) {

        return value;

    }


    let filterIndex: number = value.toLowerCase().indexOf(filterText);

    if (filterIndex < 0) {

        return null;

    } 

    return value.substr(0, filterIndex) 

        + "<span class='search-highlight'>" 

        + value.substr(filterIndex, filterText.length) 

        + "</span>" 

        +   value.substr(filterIndex + filterText.length, value.length - (filterIndex + filterText.length));

}

因此,为了使用 html 管理对字符串的搜索,我创建了可以使用 html 搜索字符串的新函数。(我在搜索正确的字符串匹配之前删除了 html 部分)


private static test(value: string, filterText: string): string {

    if (value == null) {

        return value;

    }

    // Check for raw data without html

    let valueWithoutHtml = TextFilterUtils.removeTextHtmlTags(value);

    let filterIndex: number = valueWithoutHtml.toLowerCase().indexOf(filterText);

    if (filterIndex < 0) {

        return null;

    } else {

        // TODO: 

        // just need to figure how we can highlight properly 

        // real issue is to identify proper index for warping   <span class='search-highlight'> </span> 

        return "";

    }

}

我们如何对 html 字符串进行变形?任何帮助或指导将不胜感激。


慕仙森
浏览 154回答 3
3回答

慕盖茨4494581

我对WYSIWYG项目有完全相同的要求。这个怎么运作 ?通过将 HTML 元素映射到它们的纯文本版本,同时保持元素的原始大小。然后对于每个匹配项,使用先前的映射和setSelectionRange选择回匹配项中包含的每个元素的相应部分正如我在这个相关问题中所解释的那样,使用execCommand标记每个。然后您可以使用getSelection()&nbsp;.anchorNode.parentElement 来获得一个现成的包装选择,在此处与您的匹配相对应。然后你可以应用任何你想要的风格!使用这种方法,您将拥有一些重要的优势:支持多项选择(我不知道单个浏览器允许使用其本机搜索进行多项选择)支持在多个元素上进行搜索传播(这里也是,大多数使用的浏览器都没有此功能)支持正则表达式:)根据需要操作匹配项,对样式没有限制,您甚至可以修改内容(例如用于自动更正目的)如果您也在进行 WYSIWYG,则映射到源窗格。(查看如何在内容窗格中选择在下面的 ACE 编辑器中突出显示相应的源)这是一个快速展示:提示&nbsp;我强烈建议您将所有 execCommand 调用放在requestAnimationFrame() 中,因为每次调用都会触发强制回流,这将使您的应用程序性能下降。通常,浏览器会触发 60 次回流/秒,但在这里,假设您有 300 个匹配项,您将添加 300 次额外的回流。通过在 requestAnimationFrame() 中调用 execCommand,您将告诉浏览器使用计划的回流而不是添加更多。

陪伴而非守候

您可以使用的一件事是Range对象的getClientRects方法:https : //developer.mozilla.org/en-US/docs/Web/API/range/getClientRects这允许您添加带有搜索坐标的 div,允许您突出显示文本而无需操作 DOM。查找节点并不是那么简单(尤其是在结构复杂的情况下),但是您可以遍历所有文本节点以匹配要搜索的元素的 textContent 中的搜索索引。因此,首先将搜索结果与 DOM 进行匹配。在示例中,我使用递归生成器,但任何递归循环都可以。基本上,您需要做的是遍历每个文本节点以匹配搜索索引。因此,您遍历每个后代节点并计算文本长度,以便将搜索与节点匹配。完成此操作后,您可以根据这些结果创建一个Range,然后添加具有使用getClientRects获得的矩形坐标的元素。通过给出 z-index 负值和绝对位置,它们将出现在文本下方的正确位置。因此,您将获得高亮效果,但不会触及您正在搜索的 HTML。像这样:document.querySelector('#a').onclick = (e) => {&nbsp; let topParent = document.querySelector('#b');&nbsp; let s, range;&nbsp; let strToSearch = document.querySelector('#search').value&nbsp; let re = RegExp(strToSearch, 'g')&nbsp; removeHighlight()&nbsp; s = window.getSelection();&nbsp; s.removeAllRanges()&nbsp; // to handle multiple result you need to go through all matches&nbsp; while (match = re.exec(topParent.textContent)) {&nbsp; &nbsp; let it = iterateNode(topParent);&nbsp; &nbsp; let currentIndex = 0;&nbsp; &nbsp; // the result is the text node, so you can iterate and compare the index you are searching to all text nodes length&nbsp; &nbsp; let result = it.next();&nbsp; &nbsp; while (!result.done) {&nbsp; &nbsp; &nbsp; if (match.index >= currentIndex && match.index < currentIndex + result.value.length) {&nbsp; &nbsp; &nbsp; &nbsp; // when we have the correct node and index we add a range&nbsp; &nbsp; &nbsp; &nbsp; range = new Range();&nbsp; &nbsp; &nbsp; &nbsp; range.setStart(result.value, match.index - currentIndex)&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; if (match.index + strToSearch.length >= currentIndex && match.index + strToSearch.length < currentIndex + result.value.length) {&nbsp; &nbsp; &nbsp; &nbsp; // when we find the end node, we can set the range end&nbsp; &nbsp; &nbsp; &nbsp; range.setEnd(result.value, match.index + strToSearch.length - currentIndex)&nbsp; &nbsp; &nbsp; &nbsp; s.addRange(range)&nbsp; &nbsp; &nbsp; &nbsp; // this is where we add the divs based on the client rects of the range&nbsp; &nbsp; &nbsp; &nbsp; addHighlightDiv(range.getClientRects())&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; currentIndex += result.value.length;&nbsp; &nbsp; &nbsp; result = it.next();&nbsp; &nbsp; }&nbsp; }&nbsp; s.removeAllRanges()}function* iterateNode(topNode) {&nbsp; // this iterate through all descendants of the topnode&nbsp; let childNodes = topNode.childNodes;&nbsp; for (let i = 0; i < childNodes.length; i++) {&nbsp; &nbsp; let node = childNodes[i]&nbsp; &nbsp; if (node.nodeType === 3) {&nbsp; &nbsp; &nbsp; yield node;&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; yield* iterateNode(node);&nbsp; &nbsp; }&nbsp; }}function addHighlightDiv(rects) {&nbsp; for (let i = 0; i < rects.length; i++) {&nbsp; &nbsp; let rect = rects[i];&nbsp; &nbsp; let highlightRect = document.createElement('DIV')&nbsp; &nbsp; document.body.appendChild(highlightRect)&nbsp; &nbsp; highlightRect.classList.add('hl')&nbsp; &nbsp; highlightRect.style.top = rect.y + window.scrollY + 'px'&nbsp; &nbsp; highlightRect.style.left = rect.x + 'px'&nbsp; &nbsp; highlightRect.style.height = rect.height + 'px'&nbsp; &nbsp; highlightRect.style.width = rect.width + 'px'&nbsp; }}function removeHighlight() {&nbsp; let highlights = document.querySelectorAll('.hl');&nbsp; for (let i = 0; i < highlights.length; i++) {&nbsp; &nbsp; highlights[i].remove();&nbsp; }}.hl {&nbsp; background-color: red;&nbsp; position: absolute;&nbsp; z-index: -1;}<input type="text" id="search" /><button id="a">search</button><div id="b">&nbsp; <h1>Lorem ipsum dolor sit amet</h1>, consectetur&nbsp; <h2>adipiscing elit, sed do</h2> eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud <strong>exercitation <span>ullamco laboris</span> nisi ut aliquip ex ea commodo</strong> consequat. Duis aute irure dolor&nbsp; in reprehenderit in voluptate velit <em>esse cillum dolore eu fugiat nulla pariatur.</em> Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>

白板的微信

因此,与其重新创建该 HTML 部分并进行一些重新渲染,不如在客户端进行。通过谷歌搜索我发现:https://markjs.io/https://www.the-art-of-web.com/javascript/search-highlight/
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript