在contenteditable div中保存光标位置

问题描述 投票:0回答:1

我有一个内容可编辑的 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 的末尾,但这在编辑不是最后一个字符的内容时会引发问题。

javascript html syntax-highlighting
1个回答
0
投票

我通过保留具有突出显示功能的

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>

© www.soinside.com 2019 - 2024. All rights reserved.