使用javascript模拟浏览器的ctrl+f查找功能

128 阅读1分钟

在线demo

测试代码地址

核心逻辑:利用 xpath+range 标记相关节点

1、首先通过xpath查找相关节点

/**
 * value: 关键词
 * contentContainer:内容区域
 * eles:查找的节点集合
 */
const xpath = `//*[contains(text(),"${value}")]`;
const targetElements = document.evaluate(xpath, contentContainer, null, XPathResult.ANY_TYPE, null);
let result = targetElements.iterateNext() as HTMLElement;
const eles = [];
while (result) {
    eles.push(result);
    result = targetElements.iterateNext() as HTMLElement;
}

2、遍历查找的节点集合,使用range标记节点

/**
 * marks:标记集合
 * markContainer:标记容器
 */
const marks: HTMLElement[] = [];
eles.forEach((ele) => {
  const startNode = ele.firstChild!;
  const index = ele.textContent!.indexOf(value);
  const range = document.createRange();
  range.setStart(startNode, index);
  range.setEnd(startNode, index + value.length);
  const { width, height, top, left } = range.getBoundingClientRect();
  const span = document.createElement('span');
  span.style.cssText = `
      width:${width}px;
      height:${height}px;
      position:absolute;
      top:${top + contentContainer.scrollTop}px;
      left:${left}px;
      background-color:rgb(253 253 6 / 50%);
  `;
  markContainer.appendChild(span);
  marks.push(span);
});

注意:markContainer应处于contentContainer的滚动区域内,否则标记的位置计算不准