Как получить количество строк в ContentEditable области и текущей позиции каретки линии?
мой вопрос состоит из двух частей, но они связаны.
во - первых-у меня есть довольный DIV с некоторым текстом, и мне нужно получить общее количество строк (строк) этого DIV. Возможно ли это ?
Secondly-мне нужно получить позицию строки каретки, если она находится на строке 1, 2, 3 и т. д....
может кто-нибудь помочь ?
1 ответов
прямой ответ заключается в том, что нет никакого метода, который на самом деле получает вам эти числа. Тем не менее, есть несколько различных обходных путей, которые вы можете применить к оценка (я использую оценка, потому что я не думаю, что они могут быть сделаны на 100% точными) эти значения.
чтобы ответить на ваш первый вопрос, Как получить количество строк в элементе. Предполагая, что элемент использует согласованный line-height
, вы можете найти количество строк, разделив элемент height
С line-height
. Это конечно значительно сложнее, если у вас есть элементы с margin
s,padding
s, или дифференцируя line-height
s внутри элемента. Если этого недостаточно, то line-height
свойство не обязательно должно быть числовым значением, т. е. оно может быть normal
или % etc. Есть довольно много вопросов относительно line-height
свойство и как получить числовое представление об этом здесь, поэтому я не буду вдаваться в подробности. Для ради остальной части моего ответа, я специально назначил общий line-height
через элемент.
гораздо более проблематичной частью вашего вопроса является поиск позиции каретки в элементе. Опять же, нет метода, который просто вернет вам правильный ответ. Вместо этого, один подход вы можете принять к оценка позиция строки каретки, чтобы сделать range
в текущем положении каретки (selection
), вставьте там фиктивный узел, получите узлы offset
относительная к контейнерам!--14-->, вычислить количество строк на основе 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/
EDIT: попробуйте 2 http://jsfiddle.net/niklasvh/mKQUH/129/
как уже упоминалось, создание фиктивных элементов каре прыгать все иногда над местом, поэтому я снова пошел с getClientRects () для диапазонов. Чтобы сделать их более осуществимыми, я сделал выбор расширить себя на один символ, затем создать диапазон, затем проверить положение прямой линии, а затем переместить курсор назад на один символ.
почему?
поскольку курсор на первом символе строки будет иметь свой верхний параметр на том же уровне, что и предыдущая строка, поэтому с применением дополнительного символа к нему он может проверить, является ли он вообще-то новая линия. Другая проблема с 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();
}
});