Получить позицию каретки в contentEditable div
Я нахожу тонны хороших, кроссбраузерных anwers о том, как установить курсор или позицию курсора в contentEditable DIV, но ни о том, как получить или найти его положение...
то, что я хочу сделать, это знать положение каретки в этом div, на keyup.
Итак, когда пользователь набирает текст, я могу в любой момент узнать положение его курсора в div.
EDIT: я ищу индекс в содержимом div (текст), а не курсор координирует.
<div id="contentBox" contentEditable="true"></div>
$('#contentbox').keyup(function() {
// ... ?
});
6 ответов:
следующий код предполагает:
- в редактируемом узле всегда есть один текстовый узел
<div>
и никаких других узлов- редактируемый div не имеет CSS
white-space
свойство имеет значениеpre
код:
function getCaretPosition(editableDiv) { var caretPos = 0, sel, range; if (window.getSelection) { sel = window.getSelection(); if (sel.rangeCount) { range = sel.getRangeAt(0); if (range.commonAncestorContainer.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; }
#caretposition { font-weight: bold; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div id="contentbox" contenteditable="true">Click me and move cursor with keys or mouse</div> <div id="caretposition">0</div> <script> var update = function() { $('#caretposition').html(getCaretPosition(this)); }; $('#contentbox').on("mousedown mouseup keydown keyup", update); </script>
попробуйте это:
каретка.js Получить положение каретки и смещение от текстового поля
$("#editable").on('keydown keyup mousedown mouseup',function(e){ if($(window.getSelection().anchorNode).is($(this))){ $('#position').html('0') }else{ $('#position').html(window.getSelection().anchorOffset); } });
body{ padding:40px; } #editable{ height:50px; width:400px; border:1px solid #000; } #editable p{ margin:0; padding:0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script> <div contenteditable="true" id="editable">move the cursor to see position</div> <div> position : <span id="position"></span> </div>
//global savedrange variable to store text range in var savedrange = null; function getSelection() { var savedRange; if(window.getSelection && window.getSelection().rangeCount > 0) //FF,Chrome,Opera,Safari,IE9+ { savedRange = window.getSelection().getRangeAt(0).cloneRange(); } else if(document.selection)//IE 8 and lower { savedRange = document.selection.createRange(); } return savedRange; } $('#contentbox').keyup(function() { var currentRange = getSelection(); if(window.getSelection) { //do stuff with standards based object } else if(document.selection) { //do stuff with microsoft object (ie8 and lower) } });
Примечание: объект диапазона его сам может быть сохранен в переменной и может быть повторно выбран в любое время, если содержимое contenteditable div не изменится.
Ссылка для IE 8 и ниже: http://msdn.microsoft.com/en-us/library/ms535872(против.85).аспн
ссылка на стандарты (все остальные) браузеры: https://developer.mozilla.org/en/DOM/range (это документы mozilla, но код работает в chrome, safari, opera и ie9 тоже)
это работает для меня:
function getCaretCharOffsetInDiv(element) { var caretOffset = 0; if (typeof window.getSelection != "undefined") { var range = window.getSelection().getRangeAt(0); var preCaretRange = range.cloneRange(); preCaretRange.selectNodeContents(element); preCaretRange.setEnd(range.endContainer, range.endOffset); caretOffset = preCaretRange.toString().length; } else if (typeof document.selection != "undefined" && document.selection.type != "Control") { var textRange = document.selection.createRange(); var preCaretTextRange = document.body.createTextRange(); preCaretTextRange.moveToElementText(element); preCaretTextRange.setEndPoint("EndToEnd", textRange); caretOffset = preCaretTextRange.text.length; } return caretOffset; }
вызывающая линия зависит от типа события, для ключевого события используйте это:
getCaretCharOffsetInDiv(e.target) + ($(window.getSelection().getRangeAt(0).startContainer.parentNode).index());
для события мыши используйте это:
getCaretCharOffsetInDiv(e.target.parentElement) + ($(e.target).index())
в этих двух случаях я забочусь о линиях разрыва, добавляя целевой индекс
function getCaretPosition() { var x = 0; var y = 0; var sel = window.getSelection(); if(sel.rangeCount) { var range = sel.getRangeAt(0).cloneRange(); if(range.getClientRects()) { range.collapse(true); var rect = range.getClientRects()[0]; if(rect) { y = rect.top; x = rect.left; } } } return { x: x, y: y }; }