<div>
  这是一个测试 Highlight API 性能的demo.(vs 使用 span 包裹节点)
</div>
<br>
<button type="button" onclick="measureTime(highlightWithAPIRanges)">Highlight with API using Ranges</button>
<button type="button" onclick="measureTime(highlightWithAPIStaticRanges)">Highlight with API using StaticRanges</button>
<button type="button" onclick="measureTime(restoreWithAPI)">Clear API highlights</button>
<br><br>
<button type="button" onclick="measureTime(highlightWithSpans)">Highlight with spans</button>
<button type="button" onclick="measureTime(restoreWithSpans)">Clear highlighted spans</button>
<br><br>
<div>你可以改变文本节点的数量: </div>
<input type="number" id="span-quantity" value="10000"><button type="button" id="generate-content-button" onclick="generateContent()">生成文本</button>
<br><br>
<div>渲染时长 <span id="performance-span">0</span>ms</div>
<br>
<span id="parent-span"></span>
body{
  padding: 15px;
}
.highlighted-with-span {
    background-color: yellow;
    color: red;
  }

  ::highlight(example-highlight) {
    background-color: cyan;
    color: blue;
  }

  body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    text-align: justify;
    font-size: 6px;
  }

  button {
    font-size: 16;
  }

  div{
    font-size: 18;
  }

  #parent-span > span {
    margin-right: 5px;
  }

  input {
    font-size: 16;
    width: 80px;
  }
const highlightedWithSpanClass = "highlighted-with-span";

  function generateContent() {
    let spansQuantity = document.getElementById("span-quantity").valueAsNumber;
    let contentTemplate = "<span>qwertyuiopasdfghjklzxcvbnm</span><wbr>";
    document.getElementById("parent-span").innerHTML = contentTemplate.repeat(spansQuantity);
  }

  generateContent();

  function measureTime(fun) {
    const start = Date.now();
    fun();
    // Force frame update before measuring end time.
    requestAnimationFrame(()=>setTimeout(()=>{
      const end = Date.now();
      let span = document.getElementById("performance-span");
      span.textContent = `${end-start}`;
    }, 0));
  }

  function doForEveryTextNode(root, operation) {
    let all = [];
    for (let node = root.firstChild; node; node = node.nextSibling) {
      if (node.nodeType == Node.TEXT_NODE) operation(node)
      else if (node.nodeName == "SCRIPT" || node.nodeName == "STYLE") continue;
      else doForEveryTextNode(node, operation);
    }
    return all;
  }

  // Fire a click event on #generate-content-button when pressing Enter key while in #span-quantity
  document.querySelector("#span-quantity").addEventListener("keyup", event => {
    if(event.key !== "Enter") return;
    document.querySelector("#generate-content-button").click();
    event.preventDefault();
  });

  /************************************************************************/

  const parentSpan = document.getElementById('parent-span');

  function highlightWithSpans() {
    doForEveryTextNode(parentSpan, wrapTextWithSpan);
  }

  function highlightWithAPIRanges() {
    let highlight = new Highlight();
    doForEveryTextNode(parentSpan, (node) => { wrapTextWithHighlightAPIRange(highlight, node) } );
    CSS.highlights.set("example-highlight", highlight);
  }

  function highlightWithAPIStaticRanges() {
    let highlight = new Highlight();
    doForEveryTextNode(parentSpan, (node) => { wrapTextWithHighlightAPIStaticRange(highlight, node) } );
    CSS.highlights.set("example-highlight", highlight);
  }

  /************************************************************************/

  function wrapTextWithSpan(textNode) {
    let span = document.createElement('span');
    span.className = "highlighted-with-span";
    textNode.parentNode.insertBefore(span, textNode.nextSibling);
    span.appendChild(textNode);
  }

  function wrapTextWithHighlightAPIRange(highlight, textNode) {
    let r = new Range();
    r.setStart(textNode, 0);
    r.setEnd(textNode, textNode.nodeValue.length);
    highlight.add(r);
  }

  function wrapTextWithHighlightAPIStaticRange(highlight, textNode) {
    let r = new StaticRange({startContainer: textNode, startOffset: 0, endContainer: textNode, endOffset: textNode.nodeValue.length});
    highlight.add(r);
  }

  /************************************************************************/

  function restoreWithSpans() {
    let spans = document.getElementsByClassName(highlightedWithSpanClass);
    while(spans.length) {
      let span = spans[0];
      span.parentNode.insertBefore(span.firstChild, span);
      span.parentNode.removeChild(span);
    }
  }

  function restoreWithAPI() {
    CSS.highlights.delete("example-highlight");
  }

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.