[英]How to get the caret position in ContentEditable elements with respect to the innerText?
I am aware that there are a lot of existing questions about getting the caret position in ContentEditable
elements.我知道有很多关于在ContentEditable
元素中获取插入符号位置的现有问题。 Almost all of those existing solutions provide the caret position with respect to the textContent
.几乎所有现有的解决方案都提供了与textContent
的插入符号位置。 Some examples are this one or this one .一些例子是this one或this one 。
We are currently developing two WebExtensions to do autocorrection as the user types.我们目前正在开发两个 WebExtensions 来根据用户类型进行自动更正。 For example, if the user types :)
, it could autocorrect it to 😀.例如,如果用户输入:)
,它可以自动更正为😀。 For the autocorrection to work, it needs to get the caret position with respect to the innerText
.为了使自动更正工作,它需要获取关于innerText
的插入符号位置。 The textContent
can include whitespace characters and other differences that do not actually appear when the text is rendered, which breaks the autocorrect feature. textContent
可以包含在呈现文本时实际不会出现的空白字符和其他差异,这会破坏自动更正功能。
Our current method is partially adapted from this answer: https://stackoverflow.com/a/29258657 , which provides the caret position with respect to the innerHTML
.我们当前的方法部分改编自这个答案: https : //stackoverflow.com/a/29258657 ,它提供了关于innerHTML
的插入符号位置。 It clones the element, inserts the null character, determines the index and then removes the null character:它克隆元素,插入空字符,确定索引,然后删除空字符:
// document.designMode is handled the same, see https://github.com/rugk/unicodify/issues/54
if (target.isContentEditable || document.designMode === "on") {
target.focus();
const _range = document.getSelection().getRangeAt(0);
if (!_range.collapsed) {
return null;
}
const range = _range.cloneRange();
const temp = document.createTextNode("\0");
range.insertNode(temp);
const caretposition = target.innerText.indexOf("\0");
temp.parentNode.removeChild(temp);
return caretposition;
}
See our original source code for the full context.有关完整上下文,请参阅我们的原始源代码。 This method seems to work fine on 99% of websites, but breaks on Twitter .这种方法似乎在 99% 的网站上都可以正常工作,但在Twitter上就失效了。 The cursor is constantly reset to the beginning of the line as the user is typing, which scrambles the text (see the corresponding issue for more information).当用户输入时,光标会不断重置到行首,这会打乱文本(有关更多信息,请参阅相应的问题)。 We are guessing that Twitter does not like the null character, but we tried with other nonprinting characters and had the same issue.我们猜测 Twitter 不喜欢空字符,但我们尝试使用其他非打印字符并遇到了同样的问题。
We are looking for another method to determine the caret position with respect to the innerText
that will work on all websites, including on Twitter.我们正在寻找另一种方法来确定有关innerText
的插入符号位置,该方法适用于所有网站,包括Twitter。 It needs to support recent versions of both Firefox and Chrome, including Firefox ESR.它需要支持 Firefox 和 Chrome 的最新版本,包括 Firefox ESR。 It also needs to be performant, since it runs on every keypress.它还需要高性能,因为它在每个按键上运行。
Cross-posted on Mozilla's Discourse .在Mozilla 的 Discourse上交叉发布。
I get the Selection
and Range
from the target
element我从target
元素获得Selection
和Range
const selection = document.getSelection();
const range = document.createRange();
After checking if the Range
is collapsed, your base code to insert the null
character and getting the caret's position检查Range
是否折叠后,您的基本代码插入null
字符并获取插入符号的位置
const temp = document.createTextNode("\0");
selection.getRangeAt(0).insertNode(temp);
caretPosition = target.innerText.indexOf("\0");
temp.parentNode.removeChild(temp);
I then use this snippet to set the caret's position, which should be the fix to Twitter然后我使用这个片段来设置插入符号的位置,这应该是对 Twitter 的修复
range.setStart(selection.focusNode, selection.focusOffset);
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);
const target = document.getElementById('text'); target.addEventListener('keyup', () => { let caretPosition = null; const selection = document.getSelection(); const range = document.createRange(); if (range.collapsed) { const temp = document.createTextNode("\\0"); selection.getRangeAt(0).insertNode(temp); caretPosition = target.innerText.indexOf("\\0"); temp.parentNode.removeChild(temp); range.setStart(selection.focusNode, selection.focusOffset); range.collapse(false); selection.removeAllRanges(); selection.addRange(range); } console.log(JSON.stringify({ caretPosition })); });
#text { border: 1px solid; padding: 1rem; width: 50vw; height: 50vh; }
<h3>ContentEditable Div</h3> <div id="text" contenteditable="true">This text can be edited by the user.<br> Some <strong>bold</strong> and <em>italic and <strong>bold</strong></em> text.</div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.