ContentEditable div - 更新内部html后设置光标位置

问题描述 投票:14回答:2

我有一个拼写检查解决方案,它使用内容可编辑的div并在拼写错误的单词周围插入span标签。每次更新div的内部html时,光标移动到div的开头。

我知道如果用户在句子的末尾添加新单词(下面的代码),我可以将光标移动到div的末尾。

旧文本:这是一个拼写检查器

新文本:这是一个拼写检查程序解决方案

var range = document.createRange();
range.selectNodeContents(element[0]);
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

但是,如果用户在句子中间添加单词,则无法保留光标位置。

旧文本:这是一个拼写检查程序

新文本:这是一个新的拼写检查器

在上面的例子中,当光标应该在“new”之后时,光标到达div的末尾。

如何保持光标位置?由于我正在更新html并添加节点,因此在更新之前保存范围并将其添加到选择对象不起作用。

提前致谢。

javascript html dom contenteditable cursor-position
2个回答
5
投票

据我所知,更改div的内容总是有问题。

所以这是我带来的解决方案。请输入错误字,如helloo,dudeee

理想情况下,这应该适用于textarea。

方案细节:

  • 使用具有相同文本内容的ghost div
  • 使用透明颜色作为ghost div
  • 使用border-bottom作为ghost div span文本
  • 更改z索引,使其不会出现在前面

// some mock logic to identify spelling error
const errorWords = ["helloo", "dudeee"];

// Find words from string like '   Helloo   world .. '
// Perhaps you could find a better library you that does this logic.
const getWords = (data) =>{
  console.log("Input: ", data);
  const allWords = data.split(/\b/);
  console.log("Output: ", allWords)
  return allWords;
}

// Simple mock logic to identify errors. Now works only for 
// two words [ 'helloo', 'dudeee']
const containsSpellingError = word => {
  const found = errorWords.indexOf(word) !== -1;
  console.log("spell check:", word, found);
  return found;
}

const processSpellCheck = text => {
  const allWords = getWords(text);
  console.log("Words in the string: ", allWords);
  const newContent = allWords.map((word, index) => {
    var text = word;
    if(containsSpellingError(word.toLowerCase())) {
      console.log("Error word found", word);
      text = $("<span />")
        .addClass("spell-error")
        .text(word);
    }
    return text;
  });
  return newContent;
}

function initalizeSpellcheck(editorRef) {
  var editorSize = editorRef.getBoundingClientRect();
  
  var spellcheckContainer = $("<div />", {})
    .addClass("spell-check")
    .prop("spellcheck", "false");
 
  var spellcheckSpan = $("<span />")
    .addClass("spell-check-text-content")
    .css({
      width: editorSize.width,
      height: editorSize.height,
      position: "absolute",
      zIndex: -1
    });
    
  var text = $(editorRef).text();
  
  var newContent = processSpellCheck(text);
  spellcheckSpan.append(newContent);
  
  spellcheckContainer.append(spellcheckSpan);
  spellcheckContainer.insertBefore(editorRef);
  
  $(editorRef).on("input.spellcheck", function(event) {
      var newText = $(event.target).text();
      var newContent = processSpellCheck(newText); 
      $(".spell-check .spell-check-text-content").text("");
      $(".spell-check .spell-check-text-content").append(newContent);
  });
}


$(document).ready(function() {
  var editor = document.querySelector("#editor");
  initalizeSpellcheck(editor);
});
#editor {
  border: 1px solid black;
  height: 200px;
}

.spell-check {
  color: transparent;
}

.spell-error {
  border-bottom: 3px solid orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<div id="editor" contenteditable="true" spellcheck="false">
dudeee
</div>

0
投票

这个答案可能适用于SitePoint:

存储选择x,y:

cursorPos=document.selection.createRange().duplicate();
clickx = cursorPos.getBoundingClientRect().left;
clicky = cursorPos.getBoundingClientRect().top;

恢复选择:

cursorPos = document.body.createTextRange();
cursorPos.moveToPoint(clickx, clicky);
cursorPos.select();

SitePoint文章:Saving/restoring caret position in a contentEditable div

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