60

contentEditable 要素 (p、div など) があり、その中のキャレット (カーソル) 位置を取得したいと考えています。通常、次のコードでそれを実現できます。

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

要素にテキストのみが含まれている場合、これは正常に機能します。ただし、要素に HTML 書式が含まれている場合、返される位置は、含まれている HTML 要素内のキャレット位置を基準にしています。

contentEditable 要素の内容がこれであると仮定しましょう:

AB<b>CD</b>EF

キャレットが の中<b></b>にある場合、たとえば C と D の間にある場合、上記のコードで返される位置は 3 ではなく 1 です (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 に答える
1

要素を挿入したい場合は、次のようなことを試みることができます。

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