Получить позицию курсора (курсора) в contentEditable области, содержащей содержимое HTML

у меня есть элемент 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 ответов


обновление

Я написал более простую версию этого, которая также работает в IE

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

Ответ

это на самом деле более полезный результат, чем символа в тексте всего документа:startOffset свойство диапазона DOM (что и есть window.getSelection().getRangeAt() returns) является смещением относительно его 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;
}

Это очень старый пост, но все же один из первых результатов поиска в 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.


Если вы хотите вставить элемент, вы можете попробовать сделать что-то вроде этого:

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