60

我有 contentEditable 元素(可以是 p、div、...),我想在其中获得插入符号(光标)的位置。我通常可以用这段代码来实现它:

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

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

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

AB<b>CD</b>EF

如果 caret 在 inside <b></b>,比方说在 C 和 D 之间,上面代码返回的位置是 1 而不是 3(从 contentEditable 元素内容的开头开始计算)

任何人都可以提出解决方案吗?

4

3 回答 3

54

更新

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

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

旧答案

这实际上是比整个文档文本中的字符偏移更有用的结果:startOffsetDOM Range 的属性(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;
}
于 2011-01-22T21:03:04.243 回答
15

这是一篇非常古老的帖子,但仍然是在 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 并将文档片段附加到临时 div 以获取 html 长度。

于 2017-10-24T04:43:05.980 回答
1

如果要插入元素,则可以尝试执行以下操作:

// Get range
var range = document.caretRangeFromPoint(event.clientX, event.clientY);
if (range)
  range.insertNode(elementWhichYouWantToAddToContentEditable);
于 2014-06-17T17:59:41.477 回答