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

时间:2011-01-22 12:41:05

标签: javascript wysiwyg contenteditable getselection

我有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元素内容的开头算起)

有人可以提出解决方案吗?

3 个答案:

答案 0 :(得分:51)

更新

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

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

旧答案

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

以下是一个实例:http://jsfiddle.net/timdown/2YcaX/

这是功能:

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

答案 1 :(得分:5)

这是一篇非常古老的帖子,但仍然是Google上搜索的第一个结果之一,所以可能仍然有用。考虑到html标签和换行符(在Firefox上测试),这对我来说也是合适的位置:

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

它使用cloneContents功能来获取实际的html并将documentfragment附加到临时div以获得html长度。

答案 2 :(得分:1)

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

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