在 contenteditable div 上检测并替换光标前的单词

Detect and replace the word before cursor on contenteditable div

如何检测 contenteditable div 中光标前的单词并用其他东西替换它? 这个 但不是 for这个内容可编辑 div:

document.getElementById('a').addEventListener('keydown', e => {
  if (e.which == 9) {
    e.preventDefault();
    let endingIndex = e.target.selectionStart;     // does not work for contenteditable
    let startingIndex = endingIndex && endingIndex - 1;
    let value = e.target.innerHTML;
    let regex = /[ ]/;

    while(startingIndex){
      if(regex.test(value[startingIndex])){
        ++startingIndex;
        break;
      }
      --startingIndex;
    }
    console.log('word before cursor: ' + value.substring(startingIndex, endingIndex));
  }
  
});
<div contenteditable id="a">Please click here and hit TAB, the word before cursor should be replaced by something else.</div>

这是因为 selectionStart 是 属性 仅适用于 HTMLInputElement 类型的对象。 也许你想直接看一下这个 gist or use Range 界面。

使用 AntonGuz 的回答建议的 gist,这适用于 contenteditable divtextarea:

function getPos(elt) {
    if (elt.isContentEditable) {  // for contenteditable
        elt.focus();
        let _range = document.getSelection().getRangeAt(0);
        let range = _range.cloneRange();
        range.selectNodeContents(elt);
        range.setEnd(_range.endContainer, _range.endOffset)
        return range.toString().length;
    } else {  // for texterea/input element
        return elt.selectionStart;
    }
}

function setPos(elt, pos) {
    if (elt.isContentEditable) {  // for contenteditable
        elt.target.focus();
        document.getSelection().collapse(elt.target, pos);
    } else {  // for texterea/input element
        elt.target.setSelectionRange(pos, pos);
    }
}

function insertText(content) {
    document.execCommand('insertText', false, content) 
}

document.addEventListener("keydown", function(e) {
    if (e.target.tagName.toLowerCase() === 'textarea' || e.target.isContentEditable)
    {        
        if (e.keyCode == 9) {
            e.preventDefault();
            console.log(getPos(e.target));
            
            let endingIndex = getPos(e.target);
            let startingIndex = endingIndex && endingIndex - 1;
            let value = e.target.isContentEditable ? e.target.innerHTML : e.target.value;
            let regex = /[ ]/;

            while (startingIndex) {
                if (regex.test(value[startingIndex])) {
                    ++startingIndex;
                    break;
                }
                --startingIndex;
            }
            console.log('word before cursor: ' + value.substring(startingIndex, endingIndex));
        }
    }
});
<div contenteditable>Please click here and hit TAB, the word before cursor should be replaced by something else.</div>

<textarea></textarea>