在包含HTML内容的contentEditable区域中获取插入(光标)位置

我有contentEditable元素(可以是p,div,…),我希望在其中插入光标(光标)的位置。 我通常可以用这段代码实现它:

var position = window.getSelection().getRangeAt(0).startOffset; 

这工作正常,而元素只包含文本。 但是,当元素包含一些HTML格式时,返回的位置是相对于包含的HTML元素中的插入位置。

我们假设contentEditable元素的内容是这样的:

 AB<b>CD</b>EF 

如果插入符号位于<b></b> ,那么在C和D之间,上面代码的返回位置是1而不是3(从contentEditable元素的内容开始算起)

任何人都可以想出解决办法吗?

UPDATE

我已经写了一个更简单的版本,也适用于IE <9:

https://stackoverflow.com/a/4812022/96100

老答案

这实际上是比整个文档中的字符偏移量更有用的结果:DOM范围的startOffset属性( window.getSelection().getRangeAt()返回的值)是相对于其startContainer属性的偏移量顺便说一下,这不一定总是一个文本节点)。 但是,如果你真的想要一个字符偏移量,这是一个function,它会做到这一点。

这里有一个生动的例子: http : //jsfiddle.net/timdown/2YcaX/

这个function:

 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; } 

这是一个非常古老的post,但仍然是在谷歌上search的第一个结果之一,所以也许还是有用的。 这对我来说正确的位置考虑HTML标签和换行(以及在Firefox上testing):

 function getCaretPosition (node) { var range = window.getSelection().getRangeAt(0), preCaretRange = range.cloneRange(), caretPosition, tmp = document.createElement("div"); preCaretRange.selectNodeContents(node); preCaretRange.setEnd(range.endContainer, range.endOffset); tmp.appendChild(preCaretRange.cloneContents()); caretPosition = tmp.innerHTML.length; return caretPosition; } 

它使用cloneContentsfunction来获取实际的html,并将documentfragment附加到一个临时div以获取html长度。

如果你想插入元素,那么你可以尝试做这样的事情:

 // Get range var range = document.caretRangeFromPoint(event.clientX, event.clientY); if (range) range.insertNode(elementWhichYouWantToAddToContentEditable);