[英]How to place the caret where it previously was after replacing the html of a contenteditable div?
I have a contenteditable div where I replace hashtags with clickable links when the user clicks on space or on enter. 我有一个contenteditable div,当用户点击空格或输入时,我用可点击的链接替换主题标签。 The user writes down:
用户写下:
I love but there is no fish at home|
我爱,但家里没有鱼
He then realizes he made a mistake and then decides to go back and write 然后他意识到他犯了一个错误然后决定回去写
I love #sushi |
我喜欢#sushi | but there is no fish at home
但家里没有鱼
#sushi
gets replaced by: 被替换为:
<a href="https://google.com/sushi>#sushi</a>
Notice that the | 请注意| shows the position of where I want the caret to be when the user presses spacebar.
显示当用户按空格键时我想要插入符号的位置。 My current "placeCaretAtEnd" function places the caret at the end of the div and NOT behind the link that I just replaced sushi with.
我当前的“placeCaretAtEnd”函数将插入符号放在div的末尾,而不是在我刚刚替换寿司的链接后面。 Is there a way to alter my current function to place the caret behind the link I just replaced in the text on the position shown above, so that the user can continue typing carelessly?
有没有办法改变我当前的功能,将插入符号放在我刚刚在上面显示的位置文本中替换的链接后面,这样用户可以继续不小心输入? So in raw html:
所以在原始的HTML:
I love < a> #sushi< /a> |
我爱<a> #sushi </ a> | but there is no fish at home
但家里没有鱼
/** * Trigger when someone releases a key on the field where you can post remarks, posts or reactions */ $(document).on("keyup", ".post-input-field", function (event) { // if the user has pressed the spacebar (32) or the enter key (13) if (event.keyCode === 32 || event.keyCode === 13) { let html = $(this).html(); html = html.replace(/(^|\\s)(#\\w+)/g, " <a href=#>$2</a>").replace("<br>", ""); $(this).html(html); placeCaretAtEnd($(this)[0]); } }); /** * Place the caret at the end of the textfield * @param {object} el - the DOM element where the caret should be placed */ function placeCaretAtEnd(el) { el.focus(); if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") { var range = document.createRange(); range.selectNodeContents(el); range.collapse(false); var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } else if (typeof document.body.createTextRange != "undefined"){ var textRange = document.body.createTextRange(); textRange.moveToElementText(el); textRange.collapse(false); textRange.select(); } }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div contenteditable="true" class="post-input-field"> I love (replace this with #sushi and type space) but there is no fish at home </div>
rangy.js has a text range module that lets you save selection as indices of the characters that are selected, and then restore it. rangy.js有一个文本范围模块 ,可以将选择保存为所选字符的索引,然后将其还原。 Since your modifications do not alter
innerText
, this looks like a perfect fit: 由于您的修改不会改变
innerText
,因此这看起来非常合适:
var sel = rangy.getSelection();
var savedSel = sel.saveCharacterRanges(this);
$(this).html(html);
sel.restoreCharacterRanges(this, savedSel);
Implementing this manually requires careful traversal of the DOM inside contenteditable
and careful arithmetics with the indices; 手动实现这个需要仔细遍历DOM内部的
contenteditable
和谨慎的算法与索引; this can't be done with a few lines of code. 用几行代码就无法做到这一点。
Your placeCaretAtEnd
can't possibly place the caret after the link you've inserted, since it doesn't "know" which (of the possibly multiple) link it is. 您的
placeCaretAtEnd
不能将插入符号放在您插入的链接之后,因为它不“知道”它(可能是多个)链接。 You have to save this information beforehand. 您必须事先保存此信息。
/** * Trigger when someone releases a key on the field where you can post remarks, posts or reactions */ $(document).on("keyup", ".post-input-field", function (event) { // if the user has pressed the spacebar (32) or the enter key (13) if (event.keyCode === 32 || event.keyCode === 13) { let html = $(this).html(); html = html.replace(/(^|\\s)(#\\w+)/g, " <a href=#>$2</a>").replace("<br>", ""); var sel = rangy.getSelection(); var savedSel = sel.saveCharacterRanges(this); $(this).html(html); sel.restoreCharacterRanges(this, savedSel); } });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-core.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-textrange.js"></script> <div contenteditable="true" class="post-input-field"> I love (replace this with #sushi and type space) but there is no fish at home </div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.