如何在不中断的情况下突出显示 html 内容字符串中的搜索文本 [英] How to highlight search text from string of html content without breaking

查看:29
本文介绍了如何在不中断的情况下突出显示 html 内容字符串中的搜索文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

private static updateFilterHTMLValue(value: string, filterText: string): string{如果(值 == 空){返回值;}让 filterIndex: number = value.toLowerCase().indexOf(filterText);如果(过滤器索引 <0){返回空;}返回值.substr(0, filterIndex)+ ""+ 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 {如果(值 == 空){返回值;}//检查没有 html 的原始数据让 valueWithoutHtml = TextFilterUtils.removeTextHtmlTags(value);让 filterIndex: number = valueWithoutHtml.toLowerCase().indexOf(filterText);如果(过滤器索引 <0){返回空;} 别的 {//去做://只需要弄清楚我们如何正确突出显示//真正的问题是为翘曲确定合适的索引 <span class='search-highlight'></span>返回 "";}}

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

解决方案

你可以使用的一件事是 Range 对象的 getClientRects 方法:https://developer.mozilla.org/en-US/docs/Web/API/范围/getClientRects

这允许您添加带有搜索坐标的 div,从而使您无需操作 DOM 即可突出显示文本.

查找节点不是那么简单(尤其是在结构复杂的情况下),但您可以遍历所有文本节点以匹配要搜索的元素的 textContent 中的搜索索引.

因此,首先将搜索结果与 DOM 匹配.在示例中,我使用递归生成器,但任何递归循环都可以.基本上,您需要做的是遍历每个文本节点以匹配搜索索引.因此,您遍历每个后代节点并计算文本长度,以便将搜索与节点匹配.

完成此操作后,您可以根据这些结果创建一个范围,然后添加具有使用 getClientRects 获得的矩形坐标的元素.通过给出 z-index 负值和绝对位置,它们将出现在文本下方的正确位置.因此,您将获得高亮效果,但不会触及您正在搜索的 HTML.像这样:

document.querySelector('#a').onclick = (e) =>{让 topParent = document.querySelector('#b');让 s,范围;让 strToSearch = document.querySelector('#search').value让 re = RegExp(strToSearch, 'g')删除突出显示()s = window.getSelection();s.removeAllRanges()//要处理多个结果,您需要遍历所有匹配项while (match = re.exec(topParent.textContent)) {让它 = iterateNode(topParent);让 currentIndex = 0;//结果是文本节点,所以你可以迭代和比较你正在搜索的索引和所有文本节点的长度让结果 = it.next();while (!result.done) {if (match.index >= currentIndex && match.index < currentIndex + result.value.length) {//当我们有正确的节点和索引时,我们添加一个范围范围 = 新范围();range.setStart(result.value, match.index - currentIndex)}if (match.index + strToSearch.length >= currentIndex && match.index + strToSearch.length < currentIndex + result.value.length) {//当我们找到结束节点时,我们可以设置范围结束range.setEnd(result.value, match.index + strToSearch.length - currentIndex)s.addRange(范围)//这是我们根据范围的客户端矩形添加 div 的地方addHighlightDiv(range.getClientRects())}currentIndex += result.value.length;结果 = it.next();}}s.removeAllRanges()}函数* iterateNode(topNode) {//遍历topnode的所有后代让 childNodes = topNode.childNodes;for (let i = 0; i < childNodes.length; i++) {让节点 = childNodes[i]如果(节点.节点类型 === 3){屈服节点;} 别的 {产量*迭代节点(节点);}}}函数 addHighlightDiv(rects) {for (let i = 0; i < rects.length; i++) {让 rect = rects[i];让 highlightRect = document.createElement('DIV')document.body.appendChild(highlightRect)highlightRect.classList.add('hl')highlightRect.style.top = rect.y + window.scrollY + 'px'highlightRect.style.left = rect.x + 'px'highlightRect.style.height = rect.height + 'px'highlightRect.style.width = rect.width + 'px'}}功能删除突出显示(){让亮点 = document.querySelectorAll('.hl');for (let i = 0; i 

.hl {背景颜色:红色;位置:绝对;z-索引:-1;}

<input type="text" id="search"/><button id="a">search</按钮><div id="b"><h1>Lorem ipsum dolor sat amet</h1>, consectetur<h2>adipiscing elit, sed do</h2>eiusmod tempor incididunt ut laboure et dolore magna aliqua.Ut enim ad minim veniam, quis nostrud <strong>exeritation <span>ullamco labouris</span>nisi ut aliquip ex ea commodo</strong>结果.Duis aute irure dolor在 voluptate velit <em>esse cillum dolore eu fugiat nulla pariatur 的 reprehenderit.</em>例外 sint occaecat cupidatat non proident, 在 culpa qui offcia deserunt mollit anim id est labourum 中被禁止.

I am looking for some solution that help to search term from html string with highlight feature. I can do this by removing html content from string. But then issue is I will not able to see it original content with highlight. I do have following function that can search & highlight string without html markup.

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));
}

So to manage the search on string with html, I created new function that can search string with html. ( I am removing html part before searching for proper string matching)

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 "";
    }
}

How can we do warping on string of html ? Any help or guidance will be really appreciated.

解决方案

One thing you can use is getClientRects method of the Range object: https://developer.mozilla.org/en-US/docs/Web/API/range/getClientRects

This allows you to add divs with the coordinates of your search, allowing you to highlight text without having to manipulate the DOM.

Finding the nodes isn't that straighforward (especially if you have a complicated structure), but you can iterate through all text nodes to match the index of the search in the textContent of the element in which you want to search.

So first you match the search result to the DOM. In the example I use a recursive generator, but any recursive loop will do. Basically what you need to do is go through every text node to match the index of a search. So you go through every descendant node and count the texts length so you can match your search to a node.

Once this is done, you can create a Range from these results, and then you add elements with the coordinates of the rectangles you get with getClientRects. By giving then a z-index negative and an absolute position, they will appear under the text at the right place. So you'll have a highlight effect, but without touching the HTML you are searching. Like this:

document.querySelector('#a').onclick = (e) => {

  let topParent = document.querySelector('#b');
  let s, range;
  let strToSearch = document.querySelector('#search').value
  let re = RegExp(strToSearch, 'g')

  removeHighlight()
  s = window.getSelection();
  s.removeAllRanges()
  // to handle multiple result you need to go through all matches
  while (match = re.exec(topParent.textContent)) {

    let it = iterateNode(topParent);
    let currentIndex = 0;
    // the result is the text node, so you can iterate and compare the index you are searching to all text nodes length
    let result = it.next();

    while (!result.done) {
      if (match.index >= currentIndex && match.index < currentIndex + result.value.length) {
        // when we have the correct node and index we add a range
        range = new Range();
        range.setStart(result.value, match.index - currentIndex)

      }
      if (match.index + strToSearch.length >= currentIndex && match.index + strToSearch.length < currentIndex + result.value.length) {
        // when we find the end node, we can set the range end
        range.setEnd(result.value, match.index + strToSearch.length - currentIndex)
        s.addRange(range)

        // this is where we add the divs based on the client rects of the range
        addHighlightDiv(range.getClientRects())


      }
      currentIndex += result.value.length;
      result = it.next();
    }
  }
  s.removeAllRanges()

}


function* iterateNode(topNode) {
  // this iterate through all descendants of the topnode
  let childNodes = topNode.childNodes;
  for (let i = 0; i < childNodes.length; i++) {
    let node = childNodes[i]
    if (node.nodeType === 3) {
      yield node;
    } else {
      yield* iterateNode(node);
    }
  }

}

function addHighlightDiv(rects) {
  for (let i = 0; i < rects.length; i++) {

    let rect = rects[i];
    let highlightRect = document.createElement('DIV')
    document.body.appendChild(highlightRect)
    highlightRect.classList.add('hl')
    highlightRect.style.top = rect.y + window.scrollY + 'px'
    highlightRect.style.left = rect.x + 'px'
    highlightRect.style.height = rect.height + 'px'
    highlightRect.style.width = rect.width + 'px'

  }

}

function removeHighlight() {
  let highlights = document.querySelectorAll('.hl');
  for (let i = 0; i < highlights.length; i++) {
    highlights[i].remove();
  }
}

.hl {
  background-color: red;
  position: absolute;
  z-index: -1;
}

<input type="text" id="search" /><button id="a">search</button>
<div id="b">
  <h1>Lorem ipsum dolor sit amet</h1>, consectetur
  <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
  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 内容字符串中的搜索文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆