admin管理员组

文章数量:1384622

I am working with a contenteditable div that will have the option to have inline html elements such as tags in the text flow.

At certain points I need to grab the caret position but have found that with the example code the position returned is incorrect if the caret is after an html child element.

I need a cross browser solution that will allow me to store the position of the caret so that it can be restored a split second later even with the presence of html elements in the text flow.

Example:

function getCaretPosition(editableDiv) {
    var caretPos = 0, containerEl = null, sel, range;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount) {
            range = sel.getRangeAt(0);
            if (rangemonAncestorContainer.parentNode == editableDiv) {
                caretPos = range.endOffset;
            }
        }
    } else if (document.selection && document.selection.createRange) {
        range = document.selection.createRange();
        if (range.parentElement() == editableDiv) {
            var tempEl = document.createElement("span");
            editableDiv.insertBefore(tempEl, editableDiv.firstChild);
            var tempRange = range.duplicate();
            tempRange.moveToElementText(tempEl);
            tempRange.setEndPoint("EndToEnd", range);
            caretPos = tempRange.text.length;
        }
    }
    return caretPos;
}

$('div').keyup(function(){
   alert(getCaretPosition(this));
});
div{width:300px; height:100px; border:solid 1px #DDD;}
div a{background:#333; color:#FFF;}
<script src=".6.4/jquery.min.js"></script>
<div contenteditable=true>
    some example text <a>anchor tag</a>&nbsp;
</div>

I am working with a contenteditable div that will have the option to have inline html elements such as tags in the text flow.

At certain points I need to grab the caret position but have found that with the example code the position returned is incorrect if the caret is after an html child element.

I need a cross browser solution that will allow me to store the position of the caret so that it can be restored a split second later even with the presence of html elements in the text flow.

Example:

function getCaretPosition(editableDiv) {
    var caretPos = 0, containerEl = null, sel, range;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount) {
            range = sel.getRangeAt(0);
            if (range.monAncestorContainer.parentNode == editableDiv) {
                caretPos = range.endOffset;
            }
        }
    } else if (document.selection && document.selection.createRange) {
        range = document.selection.createRange();
        if (range.parentElement() == editableDiv) {
            var tempEl = document.createElement("span");
            editableDiv.insertBefore(tempEl, editableDiv.firstChild);
            var tempRange = range.duplicate();
            tempRange.moveToElementText(tempEl);
            tempRange.setEndPoint("EndToEnd", range);
            caretPos = tempRange.text.length;
        }
    }
    return caretPos;
}

$('div').keyup(function(){
   alert(getCaretPosition(this));
});
div{width:300px; height:100px; border:solid 1px #DDD;}
div a{background:#333; color:#FFF;}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<div contenteditable=true>
    some example text <a>anchor tag</a>&nbsp;
</div>

Original JSFiddle: http://jsfiddle/wPYMR/2/

Share Improve this question edited Dec 28, 2021 at 17:47 General Grievance 5,04338 gold badges37 silver badges56 bronze badges asked May 10, 2011 at 14:45 wilsonpagewilsonpage 17.6k23 gold badges105 silver badges150 bronze badges 2
  • What happens (or can happen) to the contents of the div during this split second? – Tim Down Commented May 10, 2011 at 15:08
  • The last word type can be removed and the caret position corrected. – wilsonpage Commented May 10, 2011 at 15:38
Add a ment  | 

2 Answers 2

Reset to default 4

I've answered a very similar question here: Editing Iframe Content in IE - problem in maintaining text selection

Here's a slightly simplified version of that answer:

If you're not changing the contents of the contenteditable element then the following functions will do. Call saveSelection() before doing whatever you need to do and restoreSelection() afterwards. If you are changing the content, I'd suggest using my Rangy library's save/restore selection module.

var saveSelection, restoreSelection;
if (window.getSelection) {
    // IE 9 and non-IE
    saveSelection = function() {
        var sel = window.getSelection(), ranges = [];
        if (sel.rangeCount) {
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                ranges.push(sel.getRangeAt(i));
            }
        }
        return ranges;
    };

    restoreSelection = function(savedSelection) {
        var sel = window.getSelection();
        sel.removeAllRanges();
        for (var i = 0, len = savedSelection.length; i < len; ++i) {
            sel.addRange(savedSelection[i]);
        }
    };
} else if (document.selection && document.selection.createRange) {
    // IE <= 8
    saveSelection = function() {
        var sel = document.selection;
        return (sel.type != "None") ? sel.createRange() : null;
    };

    restoreSelection = function(savedSelection) {
        if (savedSelection) {
            savedSelection.select();
        }
    };
}

Example use:

var sel = saveSelection();
// Do stuff here
restoreSelection(sel);
        var display = $("#autoplete");
        var editArea = $('#editArea');    
        console.log(e.target.selectionStart);           
        var pos = $("#editArea").caret();
        var offset = editArea.offset();
        // now you can use left, top(they are relative position)
        display.css({
            left: offset.left + 10,
            top:  offset.top + 13,
            color : "#449"
        })
        display.toggleClass("show");
        return false;

本文标签: javascriptHow to get caret position within contenteditable div with html child elementsStack Overflow