我有一个contentEditable
div,innerHTML
它可以在编辑时通过 AJAX 更新。问题是,当您更改 div 的内容时,它会将光标移动到 div 的末尾(或根据浏览器失去焦点)。在更改之前存储插入符号位置innerHTML
然后恢复它的良好跨浏览器解决方案是什么?
保存和恢复 contentEditable div 的插入符号位置
IT技术
javascript
jquery
contenteditable
2021-02-28 02:09:16
3个回答
回到 2016 年 :)
在我在这里遇到解决方案后,它们不适合我,因为每次输入后我的 DOM 都被完全替换了。我做了更多的研究,并提供了一个简单的解决方案,可以按角色的位置保存光标,这对我来说是完美的。
这个想法很简单。
- 找到插入符号前的字符长度并保存。
- 改变DOM。
- 使用
TreeWalker
走刚上text nodes
的context node
和计数的字符,直到我们得到了正确的text node
和里面的位置
两种边缘情况:
内容完全删除所以没有
text node
:
所以:将光标移动到上下文节点的开头内容少于
index
指向的内容:
因此:将光标移动到最后一个节点的末尾
function saveCaretPosition(context){
var selection = window.getSelection();
var range = selection.getRangeAt(0);
range.setStart( context, 0 );
var len = range.toString().length;
return function restore(){
var pos = getTextNodeAtPosition(context, len);
selection.removeAllRanges();
var range = new Range();
range.setStart(pos.node ,pos.position);
selection.addRange(range);
}
}
function getTextNodeAtPosition(root, index){
const NODE_TYPE = NodeFilter.SHOW_TEXT;
var treeWalker = document.createTreeWalker(root, NODE_TYPE, function next(elem) {
if(index > elem.textContent.length){
index -= elem.textContent.length;
return NodeFilter.FILTER_REJECT
}
return NodeFilter.FILTER_ACCEPT;
});
var c = treeWalker.nextNode();
return {
node: c? c: root,
position: index
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.min.js"></script>
<link href="https://rawgit.com/PrismJS/prism/gh-pages/themes/prism.css" rel="stylesheet"/>
<style>
*{
outline: none
}
</style>
<h3>Edit the CSS Snippet </H3>
<pre>
<code class="language-css" contenteditable=true >p { color: red }</code>
</pre>
<script >
var code = document.getElementsByTagName('code')[0];
code.addEventListener('input',function () {
var restore = saveCaretPosition(this);
Prism.highlightElement(this);
restore();
})
</script>
我知道这是一个古老的线程,但我想我会提供一个替代的非库解决方案
http://jsfiddle.net/6jbwet9q/9/
在 chrome、FF 和 IE10+ 中测试允许您在保留插入符号位置/选择的同时更改、删除和恢复 html。
HTML
<div id=bE contenteditable=true></div>
JS
function saveRangePosition()
{
var range=window.getSelection().getRangeAt(0);
var sC=range.startContainer,eC=range.endContainer;
A=[];while(sC!==bE){A.push(getNodeIndex(sC));sC=sC.parentNode}
B=[];while(eC!==bE){B.push(getNodeIndex(eC));eC=eC.parentNode}
return {"sC":A,"sO":range.startOffset,"eC":B,"eO":range.endOffset};
}
function restoreRangePosition(rp)
{
bE.focus();
var sel=window.getSelection(),range=sel.getRangeAt(0);
var x,C,sC=bE,eC=bE;
C=rp.sC;x=C.length;while(x--)sC=sC.childNodes[C[x]];
C=rp.eC;x=C.length;while(x--)eC=eC.childNodes[C[x]];
range.setStart(sC,rp.sO);
range.setEnd(eC,rp.eO);
sel.removeAllRanges();
sel.addRange(range)
}
function getNodeIndex(n){var i=0;while(n=n.previousSibling)i++;return i}
更新:我已经将 Rangy 的代码移植到了一个独立的 Gist:
https://gist.github.com/timdown/244ae2ea7302e26ba932a43cb0ca3908
原答案
您可以使用Rangy,我的跨浏览器范围和选择库。它有一个选择保存和恢复module,似乎非常适合您的需要。
该方法并不复杂:它在每个选定范围的开头和结尾插入标记元素,并在以后使用这些标记元素再次恢复范围边界,这可以在没有 Rangy 的情况下实现,代码不多(您甚至可以改编Rangy 自己的代码)。Rangy 的主要优点是支持 IE <= 8。
其它你可能感兴趣的问题