<label>搜索 <input id="query" type="text"></label>
<article>
  <p>
    阅文旗下囊括 QQ 阅读、<strong>起点中文网</strong>、新丽传媒等业界知名品牌,汇聚了强大的创作者阵营、丰富的作品储备,覆盖 200 多种内容品类,触达数亿用户,已成功输出《庆余年》《赘婿》《鬼吹灯》《全职高手》《斗罗大陆》《琅琊榜》等大量优秀网文 IP,改编为动漫、影视、游戏等多业态产品。
  </p>
  <p>
    《盗墓笔记》最初连载于起点中文网,是南派三叔成名代表作。2015年网剧开播首日点击破亿,开启了盗墓文学 IP 年。电影于2016年上映,由井柏然、鹿晗、马思纯等主演,累计票房10亿元。
  </p>
  <p>
    庆余年》是阅文集团白金作家猫腻的作品,自2007年在起点中文网连载,持续保持历史类收藏榜前五位。改编剧集成为2019年现象级作品,播出期间登上微博热搜百余次,腾讯视频、爱奇艺双平台总播放量突破160亿次,并荣获第26届白玉兰奖最佳编剧(改编)、最佳男配角两项大奖。
  </p>
  <p>《鬼吹灯》是天下霸唱创作的经典悬疑盗墓小说,连载于起点中文网。先后进行过漫画、游戏、电影、网络电视剧的改编,均取得不俗的成绩,是当之无愧的超级IP。</p>
</article>
body{
  background-color: azure;
}
label{
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}
body{
  padding: 15px;
}
::highlight(search-results) {
  background-color: #f06;
  color: white;
}
const query = document.getElementById("query");
const article = document.querySelector("article");

// 创建 createTreeWalker 迭代器,用于遍历文本节点,保存到一个数组
const treeWalker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);
const allTextNodes = [];
let currentNode = treeWalker.nextNode();
while (currentNode) {
  allTextNodes.push(currentNode);
  currentNode = treeWalker.nextNode();
}

// 监听inpu事件
query.addEventListener("input", () => {
  // 判断一下是否支持 CSS.highlights
  if (!CSS.highlights) {
    article.textContent = "CSS Custom Highlight API not supported.";
    return;
  }

  // 清除上个高亮
  CSS.highlights.clear();

  // 为空判断
  const str = query.value.trim().toLowerCase();
  if (!str) {
    return;
  }

  // 查找所有文本节点是否包含搜索词
  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;
      }

      // 根据搜索词的位置创建选区
      return indices.map((index) => {
        const range = new Range();
        range.setStart(el, index);
        range.setEnd(el, index + str.length);
        return range;
      });
    });

  // 创建高亮对象
  const searchResultsHighlight = new Highlight(...ranges.flat());

  // 注册高亮
  CSS.highlights.set("search-results", searchResultsHighlight);
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.