简体   繁体   English

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

[英]ContentEditable div - set cursor position after updating inner html

I have a spell check solution that uses a content editable div and inserts span tags around words that are misspelled.我有一个拼写检查解决方案,它使用内容可编辑的div并在拼写错误的单词周围插入span标签。 Every time the inner html of the div is updated, the cursor moves to the beginning of the div .每次更新div的内部 html 时,光标都会移动到div的开头。

I know I can move the cursor to the end of the div if the user adds new words to the end of the sentence (code below).我知道如果用户在句子的末尾添加新单词(下面的代码),我可以将光标移动到div的末尾。

Old Text: This is a spell checker|旧文本:这是拼写检查器|

New Text: This is a spell checker soluuution|新文本:这是一个拼写检查解决方案|

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

However, I am unable to retain the cursor position if the user adds words in the middle of a sentence.但是,如果用户在句子中间添加单词,我将无法保留光标位置。

Old Text: This is a spell checker旧文本:这是一个拼写检查器

New Text: This is a new spell checker|新文本:这是一个新的拼写检查器|

In the above case, the cursor goes to the end of the div when it should be after "new".在上面的例子中,光标在应该在“new”之后的时候移动到div的末尾。

How do I retain the cursor position?如何保留光标位置? Since I am updating the html and adding nodes, saving the range before the update and adding it to the selection object isn't working.由于我正在更新 html 并添加节点,因此在更新之前保存范围并将其添加到选择对象中不起作用。

Thanks in advance.提前致谢。

As far as I know, changing the content of the div will always have problem.据我所知,改变div的内容总会有问题。

So here is the solution that I came with.所以这是我带来的解决方案。 Please type error word such as helloo, dudeee请输入错误词,例如 hello, dudeee

This should ideally work for textarea as well.理想情况下,这也适用于 textarea。

Solution details:解决方案详情:

  • Use a ghost div with same text content使用具有相同文本内容的幽灵 div
  • Use transparent color for the ghost div为幽灵 div 使用透明颜色
  • Use border-bottom for the ghost div span text为幽灵 div 跨度文本使用 border-bottom
  • Change zIndex so that it does't appear infront更改 zIndex 使其不会出现在前面

 // 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>

This answer might work from SitePoint:这个答案可能适用于 SitePoint:

Store the selection x, y:存储选择 x, y:

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

Restore the selection:恢复选择:

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

SitePoint Article: Saving/restoring caret position in a contentEditable div SitePoint 文章: 在 contentEditable div 中保存/恢复插入符号位置

Update 25.10.2019: 2019 年 10 月 25 日更新:

The solution mentioned above doesn't work anymore since functions are used that are deprecated.上面提到的解决方案不再起作用,因为使用了不推荐使用的函数。 Does chrome supports document.selection? chrome 支持 document.selection 吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM