简体   繁体   English

如何获取 ContentEditable 元素中关于innerText 的插入符号位置?

[英]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 onethis 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上交叉发布。

Steps脚步


I get the Selection and Range from the target element我从target元素获得SelectionRange

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.

相关问题 如何使用 html 子元素在 contenteditable div 中获取插入符号 position? - How to get caret position within contenteditable div with html child elements? 在contenteditable div中获取插入符号相对于窗口的视觉位置 - Get caret's visual position with respect to window in contenteditable div 获取内容Editable caret position - Get contentEditable caret position 如何在Internet Explorer中使用html子元素在contenteditable div中获取插入位置 - How to get caret position within contenteditable div with html child elements in Internet Explorer 如何从 contenteditable 获得“删除插入符号位置”? - How can I get the "drop caret position" from contenteditable? 如何获得包含图像的contenteditable div的插入位置 - how to get the caret position of a contenteditable div which contains images 如何获得内容可编辑的插入符号位置 - How can I get the caret position on a contenteditable <button> 如何在 contentEditable div 中获取插入符号 x 和 y 位置 - How to get caret x and y position in contentEditable div 如何在 contenteditable 中获取和设置插入符号位置? - How do you get and set the caret position in a contenteditable? 如何使用contentEditable从iframe中的当前插入位置获取像素偏移量 - How to get the pixel offset from the current caret position in an iframe with contentEditable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM