CSS Custom Highlight API

CSS Custom Highlight API

CSS Custom Highlight API
JavaScript 创建范围并使用 CSS 定义样式来设置文档中任意文本范围的样式
该 API 允许开发者通过 CSS 自定义属性来设置文本的样式, 并将其应用到文档中的任意文本范围。
本质就是查找所有文本节点,收集匹配内容的 Range, 最后作为参数构建 Highlight 对象, 但需要注意的是其并未产生新的节点


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0" />
    <title>CSS Custom Highlight API</title>
    <style>
      .text {
        overflow-wrap: break-word;
        word-break: keep-all;
        white-space: pre-wrap;
        text-wrap: wrap;

        &::highlight(my-custom-highlight) {
          background-color: hotpink;
        }
      }
    </style>
  </head>
  <body>
    <strong>CSS Custom Highlight API</strong>
    <hr />
    <div>
      <span>搜索文本:&nbsp;</span>
      <input type="text" id="searchText" />
    </div>
    <p class="text">
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Aperiam nisi animi mollitia rem,
      placeat sint recusandae ab voluptatum, consequatur excepturi voluptatem repudiandae sed
      tempora, itaque optio distinctio ratione minus libero! Culpa eius, sint unde blanditiis
      deserunt molestiae beatae illum quidem quo alias modi aut adipisci in quia doloribus quisquam
      fugiat vero ut? Corrupti provident cupiditate velit quasi praesentium numquam ratione.
    </p>

    <script>
      // CSS Custom Highlight API
      // JavaScript 创建范围并使用 CSS 定义样式来设置文档中任意文本范围的样式
      // 该 API 允许开发者通过 CSS 自定义属性来设置文本的样式, 并将其应用到文档中的任意文本范围。
      // 就是查找所有文本节点,收集匹配内容的 Range, 最后作为参数构建 HighLight 对象, 但需要注意的是其并未产生新的节点

      const searchText = document.getElementById('searchText');
      const article = document.querySelector('.text');

      // 创建一个 TreeWalker 对象来遍历文档中的所有文本节点
      const treeWalker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);
      // console.log('treeWalker => ', treeWalker);
      const allTextNodes = [];
      let currentNode = treeWalker.nextNode();
      while (currentNode) {
        allTextNodes.push(currentNode);
        currentNode = treeWalker.nextNode();
      }

      searchText.addEventListener('input', () => {
        // 清空高亮效果
        CSS.highlights.clear();

        const searchValue = searchText.value.trimStart().trimEnd();
        if (searchValue === '') return;

        const ranges = allTextNodes.map((node) => {
          const text = node.textContent;
          // 所匹配的位置
          const indices = [];
          // 记录所有匹配的位置
          let startPos = 0;

          // 保存所有匹配的位置
          while (startPos < text.length) {
            const index = text.indexOf(searchValue, startPos);
            if (index === -1) break;
            indices.push(index);
            startPos = index + searchValue.length;
          }

          return indices.map((index) => {
            // 构建一个 Range 对象
            const range = new Range();
            // 设置 Range 的开始和结束位置
            range.setStart(node, index);
            range.setEnd(node, index + searchValue.length);
            return range;
          });
        });
        // console.log('ranges => ', ranges);

        // 构建一个 Highlight 对象并应用到文档中
        const searchResults = new Highlight(...ranges.flat());

        // 高亮效果
        CSS.highlights.set('my-custom-highlight', searchResults);
      });
    </script>
  </body>
</html>
posted @ 2024-04-29 22:39  _clai  阅读(34)  评论(0编辑  收藏  举报