CSS 自定義高亮 API

CSS 自定義高亮 API 提供了一種方法,可以通過使用 JavaScript 創(chuàng)建范圍并使用 CSS 定義樣式來設(shè)置文檔中任意文本范圍的樣式。

參考原文:CSS 自定義高亮 API

概念與用法

在網(wǎng)頁上設(shè)置文本范圍樣式非常有用。例如,文本編輯類的 Web 應(yīng)用程序會(huì)突出顯示拼寫或語法錯(cuò)誤,代碼編輯器會(huì)突出顯示語法錯(cuò)誤。

CSS 自定義高亮 API 通過提供一種創(chuàng)建任意 Range 對象并設(shè)置其樣式的方法(而不是局限于瀏覽器定義的范圍),擴(kuò)展了其他高亮偽元素的概念,例如 ::selection::spelling-error、::grammar-error::target-text。

使用 CSS 自定義高亮 API,你可以通過編程方式創(chuàng)建文本范圍并高亮顯示它們,而不會(huì)影響頁面中的 DOM 結(jié)構(gòu)。

使用 CSS 自定義高亮 API 設(shè)置網(wǎng)頁上文本范圍的樣式有四個(gè)步驟:

  1. 創(chuàng)建 Range 對象。
  2. 為這些范圍創(chuàng)建 Highlight 對象。
  3. 使用 HighlightRegistry 進(jìn)行注冊。
  4. 使用 ::highlight() 偽元素定義高亮樣式。

創(chuàng)建范圍

第一步是使用 JavaScript 創(chuàng)建 Range 對象,標(biāo)明你想設(shè)置樣式的文本范圍。例如:

const parentNode = document.getElementById("foo");

const range1 = new Range();
range1.setStart(parentNode, 10);
range1.setEnd(parentNode, 20);

const range2 = new Range();
range2.setStart(parentNode, 40);
range2.setEnd(parentNode, 60);

創(chuàng)建高亮

第二步是為你的文本范圍實(shí)例化 Highlight 對象

多個(gè)范圍可以關(guān)聯(lián)到一個(gè)高亮顯示。如果你希望以相同的方式高亮顯示多個(gè)文本片段,只需要?jiǎng)?chuàng)建一個(gè)高亮并使用相應(yīng)的范圍初始化它。

const highlight = new Highlight(range1, range2);

但你也可以根據(jù)需要?jiǎng)?chuàng)建任意多的高亮。例如,如果你正在構(gòu)建一個(gè)協(xié)作文本編輯器,其中每個(gè)用戶獲得不同的文本顏色,那么你可以為每個(gè)用戶創(chuàng)建一個(gè)高亮顯示,如下所示:

const user1Highlight = new Highlight(user1Range1, user1Range2);
const user2Highlight = new Highlight(user2Range1, user2Range2, user2Range3);

每個(gè)高亮可以設(shè)置不同的樣式。

注冊高亮

創(chuàng)建高亮顯示后,使用 HighlightRegistry 將其注冊為 CSS.highlights。

注冊表是一個(gè)類 Map 對象,用于通過名稱注冊高亮,如下所示:

CSS.highlights.set("user-1-highlight", user1Highlight);
CSS.highlights.set("user-2-highlight", user2Highlight);

在上面的代碼片段中,user-1-highlight 和 user-2-highlight 是自定義標(biāo)識(shí)符,用于將 CSS 中的樣式應(yīng)用到已注冊的高亮顯示上。

你可以在注冊表中注冊任意數(shù)量的高亮顯示,也可以刪除高亮顯示并清除整個(gè)注冊表。

// 從注冊表中刪除一個(gè)高亮顯示。
CSS.highlights.delete("user-1-highlight");

// 清除注冊表。
CSS.highlights.clear();

高亮樣式

最后一步是為已注冊高亮顯示設(shè)置樣式??梢允褂?::highlight() 偽元素來完成。例如,為上一步注冊的 user-1-highlight 設(shè)置高亮樣式:

::highlight(user-1-highlight) {
  background-color: yellow;
  color: black;
}

接口

Highlight
此接口用于表示要在文檔上設(shè)置樣式的范圍集合。
HighlightRegistry
可以通過 CSS.highlights 訪問,類 Map 對象用于使用自定義標(biāo)識(shí)符注冊高亮顯示。

示例

高亮顯示搜索結(jié)果
本示例展示了如何使用 CSS 自定義高亮 API 高亮顯示搜索結(jié)果。

HTML

下面的 HTML 代碼片段定義了一個(gè)搜索框和有幾段文字的文章:

<label>Search within text <input id="query" type="text" /></label>
<article>
  <p>
    Maxime debitis hic, delectus perspiciatis laborum molestiae labore,
    deleniti, quam consequatur iure veniam alias voluptas nisi quo. Dolorem
    eaque alias, quo vel quas repudiandae architecto deserunt quidem, sapiente
    laudantium nulla.
  </p>
  <p>
    Maiores odit molestias, necessitatibus doloremque dolor illum reprehenderit
    provident nostrum laboriosam iste, tempore perferendis! Ab porro neque esse
    voluptas libero necessitatibus fugiat, ex, minus atque deserunt veniam
    molestiae tempora? Vitae.
  </p>
  <p>
    Dolorum facilis voluptate eaque eius similique ducimus dignissimos assumenda
    quos architecto. Doloremque deleniti non exercitationem rerum quam alias
    harum, nisi obcaecati corporis temporibus vero sapiente voluptatum est
    quibusdam id ipsa.
  </p>
</article>

JavaScript

使用 JavaScript 監(jiān)聽搜索框上的 input 事件,當(dāng)事件觸發(fā),這段代碼將在文章的文本中為輸入文本查找匹配項(xiàng)。然后它創(chuàng)建匹配的范圍,并使用 CSS 自定義高亮 API 創(chuàng)建并注冊一個(gè) search-results 高亮對象:

const query = document.getElementById("query");
const article = document.querySelector("article");

// 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);
});

CSS

最后,在 CSS 中使用 ::highlight() 偽元素來設(shè)置高亮樣式。

::highlight(search-results) {
  background-color: #f06;
  color: white;
}

結(jié)果

結(jié)果如下所示。在輸入框中輸入文本就可以顯示高亮匹配了:

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容