Получить позицию каретки в contentEditable div
Я нахожу тонны хороших, crossbrowser 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>
попробуйте это:
каретка.Яш Получить позицию каретки и смещение от текстового поля
$("#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 (VS.85).aspx
ссылка на стандарты (все остальные) браузеры: 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
};
}