段落中特定文字高亮

段落中特定文字高亮

方法一:正则

highlightText(text, keywords) {
    keywords.forEach(keyword => {
        // 'gi' 标志表示全局搜索并且不区分大小写
       const regex = new RegExp(`(${keyword})`, 'gi');
        //匹配出相关的结果
        text = text.replace(regex, '<span class="highlight">$1</span>');
     });
    return text;
}

方法二:CSS 自定义高亮 API

CSS 自定义高亮 API 提供了一种方法,可以通过使用 JavaScript 创建范围并使用 CSS 定义样式来设置文档中任意文本范围的样式。

  • 概念与用法
    在网页上设置文本范围样式非常有用。例如,文本编辑类的 Web 应用程序会突出显示拼写或语法错误,代码编辑器会突出显示语法错误。

CSS 自定义高亮 API 通过提供一种创建任意 Range 对象并设置其样式的方法(而不是局限于浏览器定义的范围),扩展了其他高亮伪元素的概念,例如 ::selection::spelling-error::grammar-error::target-text

使用 CSS 自定义高亮 API,你可以通过编程方式创建文本范围并高亮显示它们,而不会影响页面中的 DOM 结构。

使用 CSS 自定义高亮 API 设置网页上文本范围的样式有四个步骤:

  1. 创建 Range 对象。
  2. 为这些范围创建 Highlight 对象。
  3. 使用 HighlightRegistry 进行注册。
  4. 使用 ::highlight()伪元素定义高亮样式。
创建范围

第一步是使用 JavaScript 创建 Range 对象,标明你想设置样式的文本范围。例如:

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);
创建高亮

第二步是为你的文本范围实例化 Highlight 对象

多个范围可以关联到一个高亮显示。如果你希望以相同的方式高亮显示多个文本片段,只需要创建一个高亮并使用相应的范围初始化它。

const highlight = new Highlight(range1, range2);

但你也可以根据需要创建任意多的高亮。例如,如果你正在构建一个协作文本编辑器,其中每个用户获得不同的文本颜色,那么你可以为每个用户创建一个高亮显示,如下所示:

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

每个高亮可以设置不同的样式。

注册高亮

创建高亮显示后,使用 HighlightRegistry 将其注册为 CSS.highlights

注册表是一个类 Map 对象,用于通过名称注册高亮,如下所示:

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

在上面的代码片段中,user-1-highlightuser-2-highlight 是自定义标识符,用于将 CSS 中的样式应用到已注册的高亮显示上。

你可以在注册表中注册任意数量的高亮显示,也可以删除高亮显示并清除整个注册表。

// 从注册表中删除一个高亮显示。
CSS.highlights.delete("user-1-highlight");

// 清除注册表。
CSS.highlights.clear();
高亮样式

最后一步是为已注册高亮显示设置样式。可以使用::highlight()伪元素来完成。例如,为上一步注册的user-1-highlight设置高亮样式:

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

Highlight
此接口用于表示要在文档上设置样式的范围集合。

HighlightRegistry
可以通过 CSS.highlights 访问,类Map 对象用于使用自定义标识符注册高亮显示。

示例
高亮显示搜索结果

本示例展示了如何使用 CSS 自定义高亮 API 高亮显示搜索结果。

HTML

下面的 HTML 代码片段定义了一个搜索框和有几段文字的文章:

<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 监听搜索框上的 input 事件,当事件触发,这段代码将在文章的文本中为输入文本查找匹配项。然后它创建匹配的范围,并使用 CSS 自定义高亮 API 创建并注册一个 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() 伪元素来设置高亮样式。

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

TreeWalker 对象用于表示文档子树中的节点和它们的位置。
TreeWalker 可以使用 Document.createTreeWalker() 方法创建。

  • createTreeWalker
常数描述
NodeFilter.SHOW_ALL显示所有节点。
NodeFilter.SHOW_ATTRIBUTE显示 Attr 节点。
NodeFilter.SHOW_CDATA_SECTION显示 CDATASection 节点。
NodeFilter.SHOW_COMMENT显示 Comment 节点。
NodeFilter.SHOW_DOCUMENT显示 Document 节点。
NodeFilter.SHOW_DOCUMENT_FRAGMENT显示 DocumentFragment 节点。
NodeFilter.SHOW_DOCUMENT_TYPE显示 DocumentType 节点。
NodeFilter.SHOW_ELEMENT显示 Element 节点。
NodeFilter.SHOW_ENTITY已弃用旧式参数,不再有效。
NodeFilter.SHOW_ENTITY_REFERENCE已弃用旧式参数,不再有效。
NodeFilter.SHOW_NOTATION已弃用旧式参数,不再有效。
NodeFilter.SHOW_PROCESSING_INSTRUCTION显示 ProcessingInstruction 节点。
NodeFilter.SHOW_TEXT显示 Text 节点。

我们在这里使用 NodeFilter.SHOW_TEXT,可以获取指定 DOM 元素的文本内容节点。

const treeWalker = document.createTreeWalker(content, NodeFilter.SHOW_TEXT);

treeWalker.nextNode()方法将当前节点移动到文档顺序中的下一个可见节点,并返回找到的节点,并 pushallTextNodes 数组中,如果不存在这样的节点,则返回 null,循环结束。 allTextNodes 会在之后用到。

let currentNode = treeWalker.nextNode();
while (currentNode) {
  allTextNodes.push(currentNode);
  currentNode = treeWalker.nextNode();
}

input 中输入关键词后,代码继续往下运行
遍历 allTextNodes,根据输入的关键词,获取匹配到的 Range

Range接口表示一个包含节点与文本节点的一部分的文档片段。

// new 一个 range,然后设置它的起始位置和结束位置。
const range = new Range();
range.setStart(el, index);
range.setEnd(el, index + str.length);
return range;

为这些范围创建一个 Highlight 对象 ,使用 HighlightRegistry 进行注册。

// 为文本范围创建自定义高亮,把二维数据转化为一维数组,
const searchResultsHighlight = new Highlight(...ranges.flat());
// 在 HighlightRegistry 中注册文本范围。
// CSS.highlights.set 添加给定名称的  `Highlight`  对象到注册表,如果该名称的对象已存在则覆盖原值。
CSS.highlights.set("search-results", searchResultsHighlight);

最后,使用 ::highlight() 伪元素定义高亮样式。

::highlight(search-results) {
  background-color: #f06;
  color: white;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值