Javascript 如何在包含HTML的contentEditable中获取光标位置?

Javascript 如何在包含HTML的contentEditable中获取光标位置?,javascript,contenteditable,cursor-position,Javascript,Contenteditable,Cursor Position,我需要在contentEditable div中获取光标位置。我从和中获得一些有用的函数 但是这些函数没有帮助,因为我需要HTML中的实际位置,这里是我需要的 如果我有: <div id="diva" contenteditable="true">Insert <b>text here</b></div> 以及: 函数getCharacterOffsetWithin(范围、节点){ var treeWalker=document.createTr

我需要在contentEditable div中获取光标位置。我从和中获得一些有用的函数

但是这些函数没有帮助,因为我需要HTML中的实际位置,这里是我需要的

如果我有:

<div id="diva" contenteditable="true">Insert <b>text here</b></div>
以及:

函数getCharacterOffsetWithin(范围、节点){ var treeWalker=document.createTreeWalker( 节点, NodeFilter.SHOW_TEXT, 功能(节点){ var noderage=document.createRange(); nodeRange.选择node(节点); 返回节点长度。比较基本点(Range.END\u到\u END,Range)<1? NodeFilter.FILTER\u接受:NodeFilter.FILTER\u拒绝; }, 假的 ); var charCount=0; while(treeWalker.nextNode()){ charCount+=treeWalker.currentNode.length; } if(range.startContainer.nodeType==3){ charCount+=range.startOffset; } 返回字符数; }
之前必须解决这个问题(我创建了一个基于web的字处理器):唯一可行的解决方案是遍历DOM树,计算innerHTML和outerHTML的长度,然后使用范围内的偏移量(如果有)

我还强烈反对使用contentEditable实现,您将花费更多的时间来修复它们的错误并试图覆盖它们的行为,而不是编写您真正想要的功能

我的实现是一个函数,它接受范围偏移并向上移动,直到到达指定的边界父级。需要记住的是,以前的兄弟姐妹很容易添加,但包装父母在长度方面很难考虑属性等

我的计算是取一个节点的整个长度
“sometext”
,减去
innerHTML的长度
,减去
标记名的长度
,然后
减去3
得到


但是,除非您控制HTML的创建,否则您的计数可能仍然是错误的,因为根据浏览器的不同,在测试长度时,一行中的多个空格将以1个字符或多个字符的形式返回。

您是否尝试过使用跨浏览器库,如?@VladMagdalin,rangy非常棒。它比我需要的更多如果我不使用contentEditable实现,我应该使用什么来代替呢。我无法实现textarea来满足我的需求。我同意你的观点,它有很多问题,而且非常混乱,因为我编写了很多代码,但是还有什么解决方案呢?为什么你不能实现textarea?隐藏的textarea是一个比iFrame或content Editable更有用的技巧。事实上,我同时使用了textarea和contentEditable。contentEditable是用户与之交互的内容,textarea是隐藏的。当用户在contentEditable中编写某些内容或设置某些样式时,它会反映在隐藏的文本区域中。因此textarea保留html标记,然后jQuery代码在两者之间架起桥梁。但是我不能单独使用textarea,因为它不支持以HTML格式显示文本。我认为你的文字处理器实现了同样的概念。不是吗?不,不是这样,通过使用textarea捕获键和粘贴事件,My使用javascript主动编辑实际的html。对于您的实现,如果您在DOM中漫游,为什么需要查看
innerHTML
outerHTML
?由于浏览器可能会生成许多潜在的DOM树的有效HTML表示形式,因此其中一个表示形式中的偏移量是没有意义的。
function getCaretCharacterOffsetWithin(element) {
var caretOffset = 0;
if (typeof window.getSelection != "undefined") {
    var range = window.getSelection().getRangeAt(0);
    var preCaretRange = range.cloneRange();
    preCaretRange.selectNodeContents(element);
    preCaretRange.setEnd(range.endContainer, range.endOffset);
    caretOffset = preCaretRange.toString().length;
} else if (typeof document.selection != "undefined" && document.selection.type != "Control") {
    var textRange = document.selection.createRange();
    var preCaretTextRange = document.body.createTextRange();
    preCaretTextRange.moveToElementText(element);
    preCaretTextRange.setEndPoint("EndToEnd", textRange);
    caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}
function getCharacterOffsetWithin(range, node) {
var treeWalker = document.createTreeWalker(
    node,
    NodeFilter.SHOW_TEXT,
    function(node) {
        var nodeRange = document.createRange();
        nodeRange.selectNode(node);
        return nodeRange.compareBoundaryPoints(Range.END_TO_END, range) < 1 ?
            NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
    },
    false
);

var charCount = 0;
while (treeWalker.nextNode()) {
    charCount += treeWalker.currentNode.length;
}
if (range.startContainer.nodeType == 3) {
    charCount += range.startOffset;
}
return charCount;
}