CSS Custom Highlight API实现代码高亮实例页面

回到相关文章 »

效果:

// 文本字符内容
const str = p.textContent;
// 手机号起始索引值
const arrIndex = str.match(/1\d{10}/g).map(tel => str.indexOf(tel));
// 创建range数组
const arrRange = arrIndex.map(start => {
  const range = new Range();
  range.setStart(p.firstChild, start + 3);
  range.setEnd(p.firstChild, start + 7);
  
  return range;
});

代码:

CSS代码:
#pre {
  color: #383a42;
  background: #fafafa;
  white-space: pre-wrap;
  -webkit-user-modify: read-write-plaintext-only;
  font-size: 1rem;
  padding: 1em 0.5em;
  outline-width: 4px;
  outline-color: cornflowerblue;
}
::highlight(built_in) {
  color: #c18401;
}
::highlight(comment) {
  color: #a0a1a7;
  font-style: italic;
}
::highlight(number) {
  color: #986801;
}
::highlight(title-class),
::highlight(title-function) {
  color: #3f3fde;
}
::highlight(string) {
  color: #50a14f;
}
::highlight(regexp) {
  color: #49b6fe;
}
::highlight(property) {
  color: #50a14f;
}
::highlight(keyword) {
  color: #a626a4;
}
HTML代码:
<pre id="pre" lang="js">...</pre>
JS代码:
const highlights = function (pre) {
  pre.normalize();
  const words = hljs.highlight(pre.textContent, {
    language: pre.getAttribute("lang")
  })._emitter.rootNode.children;

  CSS.highlights.clear();
  // const el = pre.firstChild
  const nodes = pre.firstChild;
  const text = nodes.textContent;
  const highlightMap = {};
  let startPos = 0;
  words
    .filter((el) => el.scope)
    .forEach((el) => {
      const str = el.children[0];
      const scope = el.scope;
      const index = text.indexOf(str, startPos);
      if (index < 0) {
        return;
      }
      const item = {
        start: index,
        scope: scope,
        end: index + str.length,
        str: str
      };
      if (highlightMap[scope]) {
        highlightMap[scope].push(item);
      } else {
        highlightMap[scope] = [item];
      }
      startPos = index + str.length;
    });

  Object.entries(highlightMap).forEach(function ([k, v]) {
    const ranges = v.map(({ start, end }) => {
      const range = new Range();
      range.setStart(nodes, start);
      range.setEnd(nodes, end);
      return range;
    });
    const highlight = new Highlight(...ranges.flat());
    CSS.highlights.set(k.replaceAll('.', '-'), highlight);
  });
};

highlights(pre);
pre.addEventListener("input", function () {
  highlights(this);
});