Как получить количество строк в ContentEditable области и текущей позиции каретки линии?

мой вопрос состоит из двух частей, но они связаны.

во - первых-у меня есть довольный DIV с некоторым текстом, и мне нужно получить общее количество строк (строк) этого DIV. Возможно ли это ?

Secondly-мне нужно получить позицию строки каретки, если она находится на строке 1, 2, 3 и т. д....

может кто-нибудь помочь ?

1 ответов


прямой ответ заключается в том, что нет никакого метода, который на самом деле получает вам эти числа. Тем не менее, есть несколько различных обходных путей, которые вы можете применить к оценка (я использую оценка, потому что я не думаю, что они могут быть сделаны на 100% точными) эти значения.

чтобы ответить на ваш первый вопрос, Как получить количество строк в элементе. Предполагая, что элемент использует согласованный line-height, вы можете найти количество строк, разделив элемент height С line-height. Это конечно значительно сложнее, если у вас есть элементы с margins,paddings, или дифференцируя line-heights внутри элемента. Если этого недостаточно, то 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();  
    }

});