我有一个内容可编辑的 div。我正在尝试实现“即时语法突出显示”。这是我到目前为止所拥有的:
const codeElement = document.getElementById('code');
// func to apply highlighting
function highlight() {
const controlRegex = /\b(function|const|let)\b/g;
const stringRegex = /["'].*["']/g;
const functionCallRegex = /[a-zA-Z_\d]*\([^)]*\)/g;
const constantRegex = /.*[a-zA-Z_\d]+\./g;
codeElement.innerHTML = codeElement.textContent.replace(stringRegex,
'<span style="color: #0d0; font-weight: normal;">$&</span>')
.replace(controlRegex, '<span style="color: pink;">$&</span>')
.replace(functionCallRegex, '<span style="color: #0bb; font-weight: bold;">$&</span>')
.replace(constantRegex, '<span style="color: yellow;">$&</span>');
}
codeElement.addEventListener('input', highlight);
highlight();
除了一个问题之外,它运行良好。每当我按下一个键时,它就会再次将光标移动到 div 的开头。
我尝试使用
window.getSelection
和 document.createRange
的组合在按下按键时将光标移动到 div 的末尾,但这在编辑不是最后一个字符的内容时会引发问题。
我通过保留具有突出显示功能的
div
来修复它,并在其顶部覆盖一个带有textarea
和color: transparent
用于输入的caret-color: white
。
const inputElement = document.getElementById("input");
const codeElement = document.getElementById("code");
function onInput(evt) {
const cInput = evt.target.value;
// func to apply highlighting
const controlRegex = /\b(function|const|let)\b/g;
const stringRegex = /["'].*["']/g;
const functionCallRegex = /[a-zA-Z_\d]*\([^)]*\)/g;
const constantRegex = /.*[a-zA-Z_\d]+\./g;
codeElement.innerHTML = cInput.replace(stringRegex,
'<span style="color: #0d0; font-weight: normal;">$&</span>')
.replace(controlRegex, '<span style="color: pink;">$&</span>')
.replace(functionCallRegex, '<span style="color: #0bb; font-weight: bold;">$&</span>')
.replace(constantRegex, '<span style="color: yellow;">$&</span>');
}
inputElement.addEventListener('input', onInput);
inputElement.focus();
pre#code,
#input {
overflow-wrap: break-word;
text-wrap: wrap;
font-size: 1rem;
font-family: monospace;
font-weight: lighter;
position: fixed;
top: -50px;
left: -10px;
right: -10px;
bottom: -50px;
;
color: white;
background-color: rgb(20, 20, 20);
padding: 60px 20px;
}
#input {
color: transparent;
caret-color: white;
background: transparent;
}
pre#code {
padding-top: calc(60px - 1em);
}
<pre id="code"></pre>
<textarea id="input" spellcheck="false"></textarea>