CSS Highlight API文本高亮搜索实例页面

回到相关文章 »

效果:

盼星星,盼月亮,我的第5本书《HTML并不简单》已经正式上架了。
这本书是围绕HTML这门语言展开的,可以说是市面上唯一一本专讲HTML的书籍。
而HTML诞生至今已有30多年,为何鲜有专门介绍这门语言的书籍呢?一方面是商业原因,另一方面则是从业人员对HTML的积累不足以撑起一本书籍的体量。
作为一个学习门槛低,收益周期长的语言,很少有人会花大量的时间在这门语言的研究上。
但我是个例外,工作至今已有15年,一直在一线开发,一直没有停止对前端基础语言的研究与学习,使得自己的知识储备足够支撑起一本干货满满,细节丰富,深入浅出的HTML书籍。
可以说,如果不是阅读了本书,很多实用的前端知识你恐怕这辈子都不会知道。

代码:

CSS代码:
::highlight(search-results) {
  background-color: yellow;
}
HTML代码:
<input type="search" id="s" placeholder="输入内容并高亮" autocomplete="off" />
<p id="p">盼星星,盼月亮,我的第5本书《HTML并不简单》已经正式上架了。
...很多实用的前端知识你恐怕这辈子都不会知道。</p>
JS代码:
const query = document.getElementById("s");
const article = document.getElementById("p");

// Find all text nodes in the article. We'll search within
// these text nodes.
const treeWalker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);
const allTextNodes = [];
let currentNode = treeWalker.nextNode();
while (currentNode) {
  allTextNodes.push(currentNode);
  currentNode = treeWalker.nextNode();
}

// Listen to the input event to run the search.
query.addEventListener("input", () => {
  // If the CSS Custom Highlight API is not supported,
  // display a message and bail-out.
  if (!CSS.highlights) {
    article.textContent = "CSS Custom Highlight API not supported.";
    return;
  }

  // Clear the HighlightRegistry to remove the
  // previous search results.
  CSS.highlights.clear();

  // Clean-up the search query and bail-out if
  // if it's empty.
  const str = query.value.trim().toLowerCase();
  if (!str) {
    return;
  }

  // Iterate over all text nodes and find matches.
  const ranges = allTextNodes
    .map((el) => {
      return { el, text: el.textContent.toLowerCase() };
    })
    .map(({ text, el }) => {
      const indices = [];
      let startPos = 0;
      while (startPos < text.length) {
        const index = text.indexOf(str, startPos);
        if (index === -1) break;
        indices.push(index);
        startPos = index + str.length;
      }

      // Create a range object for each instance of
      // str we found in the text node.
      return indices.map((index) => {
        const range = new Range();
        range.setStart(el, index);
        range.setEnd(el, index + str.length);
        return range;
      });
    });

  // Create a Highlight object for the ranges.
  const searchResultsHighlight = new Highlight(...ranges.flat());

  // Register the Highlight object in the registry.
  CSS.highlights.set("search-results", searchResultsHighlight);
});