Прямой ответ заключается в том, что не существует метода, который на самом деле получает эти цифры.Однако существует ряд различных обходных путей, которые вы можете применить к оценке (я использую оценку , потому что я не думаю, что они могут быть сделаны на 100% точными) этих значений.
Чтобы ответить на ваш первый вопрос, как узнать количество строк в элементе.Предполагая, что элемент использует согласованное line-height
, вы можете найти количество строк, разделив элемент height
на line-height
.Это, конечно, значительно усложняется, если вы получаете элементы с margin
s, padding
s или дифференцированием line-height
s внутри элемента.Если проблемы недостаточно, свойство line-height
не обязательно должно быть числовым значением, т. Е. Оно может быть normal
или% и т. Д. Существует довольно много вопросов, касающихся свойства line-height
икак получить численное представление об этом здесь, на SO, поэтому я не буду вдаваться в подробности по этому вопросу.В остальной части моего ответа я специально назначил общий элемент line-height
для элемента.
Гораздо более проблематичная часть вашего вопроса - найти позицию каретки внутри элемента.Опять же, нет метода, который просто вернет вам правильный ответ.Вместо этого, вы можете воспользоваться оценкой позиции строки каретки: сделать range
в текущей позиции каретки (selection
), вставить туда фиктивный узел, получить узлы offset
относительнодля контейнеров offset
, рассчитайте количество строк на основе top offset
этого, а затем удалите фиктивный элемент.
Дополнительные проблемы с фиктивным элементом возникают, когда вы не можете hide()
егоили оставьте это пустым.
Кажется, это очень плохой способ сделать это, и это так.Это, конечно, не работает безупречно при попытке навигации со стрелками.Так почему бы просто не использовать getClientRects()
для selection
?Он прекрасно работает, когда это просто текст без пробелов или чего-то подобного, но сразу же, если вы добавите туда несколько <br /><br />
, он больше не вернет вам позицию строки там.Кроме того, когда вы находитесь на первом или последнем символе строки, иногда получаются неправильные строки, так как элемент выбрасывается вверх или вниз в зависимости от количества доступного пространства.
Если вы ищетедля надежного способа определения положения каретки и количества линий, не один .Если грубых оценок достаточно, то мое решение - хорошее начало (оно, безусловно, могло бы потребовать дополнительной работы и поддержки IE, которая в этом случае должна быть намного проще, поскольку объект TextRange
фактически дает смещения в пикселях).
Мой взгляд на это:
var lineHeight = parseInt($('#editable').css('line-height'));
//var ce = $('#editable')[0].getClientRects();
var ce = $('#editable').position();
console.log("Lines: "+$('#editable').height()/lineHeight);
$('#editable').bind('click keyup keydown',function(){
if(window.getSelection){
range = window.getSelection().getRangeAt(0);
range.insertNode($('<canvas />').attr('id','tempCaretFinder')[0]);
var p = $('canvas#tempCaretFinder').position();
$('canvas#tempCaretFinder').remove();
console.log("Caret line: "+(Math.ceil((p.top-ce.top)/lineHeight)+1));
}else if(document.selection) {
// the IE way, which should be relatively easier. as TextRange objects return offsets directly.
range = document.selection.createRange();
}
});
Пример: http://jsfiddle.net/niklasvh/mKQUH/
РЕДАКТИРОВАТЬ: Попробуйте 2 http://jsfiddle.net/niklasvh/mKQUH/129/
Как уже упоминалось,создание фиктивных элементов иногда заставляло карету перепрыгивать повсюду, поэтому я снова попробовал использовать getClientRects () для диапазонов.Чтобы сделать их более выполнимыми, я сделал выделение, расширяющее себя на один символ, затем создал диапазон, затем проверил положение Rect и затем переместил курсор назад на один символ.
Почему?
Поскольку каретка в первом символе строки будет иметь свой верхний параметр на том же уровне, что и предыдущая строка, поэтому при применении к ней дополнительного символа она можетпроверьте, действительно ли это новая строка.Другая проблема с getClientRects () заключалась в том, что он не работал при пустых переносах строк.Для этого я использовал предыдущее создание фиктивного элемента в качестве запасного варианта в этих ситуациях.
Конечный результат:
var lineHeight = parseInt($('#editable').css('line-height'));
//var ce = $('#editable')[0].getClientRects();
var ce = $('#editable').offset();
console.log("Lines: "+$('#editable').height()/lineHeight);
$('#editable').bind('click keyup keydown',function(e){
//alert($(window).scrollTop());
if(window.getSelection){
var save = window.getSelection();
var s = window.getSelection();
s.modify('extend','forward','character');
// s.modify('extend','forward','line');
range = s.getRangeAt(0);
var p = range.getClientRects();
var top;
//console.log(p);
if (typeof p[1] != "undefined"){
top = p[1].top+$(window).scrollTop();
}else if (typeof p[0] != "undefined"){
top = p[0].top+$(window).scrollTop();
}
else{
// sigh... let's make a real work around then
range.insertNode($('<canvas />').attr('id','tempCaretFinder')[0]);
var p = $('canvas#tempCaretFinder').offset();
$('canvas#tempCaretFinder').remove();
top = p.top;
}
// console.log(top-ce.top);
console.log("Caret line: "+(Math.ceil((top-ce.top)/lineHeight)));
save.modify('move','backward','character');
/*
range = s.getRangeAt(0);
range.insertNode($('<canvas />').attr('id','tempCaretFinder')[0]);
var p = $('canvas#tempCaretFinder').position();
$('canvas#tempCaretFinder').remove();
console.log("Caret line: "+(Math.ceil((p.top-ce.top)/lineHeight)+1));
console.log(e.which);
switch(e.which){
case 40:
s.modify("move", "forward","line");
break;
case 38:
s.modify("move", "backward","lineboundary");
break;
}
*/
}else if(document.selection) {
// the IE way, which should be relatively easier. as TextRange objects return offsets directly.
range = document.selection.createRange();
}
});