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