在 HTML 中的特定元素中搜索文本并返回其 Range 对象

Search text in a particular element in the HTML and return the Range object for it

提问人:Abreham 提问时间:8/10/2022 最后编辑:Abreham 更新时间:9/6/2022 访问量:272

问:

我想在 HTML 元素中搜索文本并返回文本的 Range 对象。我想使用范围进行一些操作,例如突出显示和替换文本。类似于 Grammarly 的错误突出显示功能。

到目前为止,我尝试过:

  1. 遍历元素的子元素以查找文本并构造 Range。但这种方法有 2 个问题。

a. 它非常慢(350 毫秒)
b.找不到一些文本

const getRangeofText = (text:string) => {
  const children = document.activeElement;
  let finalNode;
  let parent = children;
  let i = 12;
  let isFound = false;
  while (parent.children.length > 0 && i > 0) {
    i--;
    console.log("I: ", i);
    console.log("traversing through: ", parent.childNodes);
    for (const item of Array.from(parent.childNodes)) {
      console.log("item: ", item);
      if (item.nodeType === 3 && item.textContent.includes(text)) {
        console.log("found in TEXT NODE");
        finalNode = item;
        isFound = true;
      }
      if (item.nodeType === 1 && item.textContent.includes(text)) {
        console.log("found in ELEMENT NODE");
        parent = item as Element;
        finalNode = item;
        isFound = true;
      }
    }
  }

  console.log("final node: ", finalNode);
  // console.log("node type: ", finalNode.nodeType);

  const range = new Range();
  let startNode;
  let endNode;
  let arr = text.split(" ");
  let startWord = arr[0];
  let endWord = arr[arr.length - 1];
  if (finalNode) {
    if (finalNode.nodeType === 1) {
      let childNodes = finalNode.childNodes;
      for (const item of Array.from(childNodes)) {
        if (item.textContent.includes(startWord)) {
          startNode = item;
        }
        if (item.textContent.includes(endWord)) {
          endNode = item;
        }
      }
     

      range.setStart(startNode, 0);
      range.setEndAfter(endNode);
    } else {
      range.setStart(finalNode, 0);
      range.setEnd(finalNode, text.length);
    }

    window.getSelection().addRange(range);
  }
};

下面是上述代码的 Codesandbox

  1. 使用 RangyfindText() 方法。这种方法也很慢(200ms)

我还有什么其他选择?或者如何优化这些功能?

javascript 全文搜索 dom-traversal rangey

评论


答:

0赞 Abreham 9/6/2022 #1
function getRanges(a) {
  let ranges = [];
  const scrollTop = document.documentElement.scrollTop;
  while (window.find(a)) {
    var rng = window.getSelection().getRangeAt(0);
    ranges = [...ranges, rng];
    document.documentElement.scrollTop = scrollTop;
  }
  return ranges;
}

const getRangeElements = (str) => {
  window.getSelection().removeAllRanges();
  const ranges = getRanges(str);
  window.getSelection().removeAllRanges();
  return ranges;
};

getRangeElements("Text to search for")

这是有效的,但它模糊了页面,并且作为焦点的任何元素(例如文本输入)都会变得模糊。有什么方法可以避免模糊吗?