Подтвердить что ты не робот

Позиция Caret в пикселях в тексте типа ввода (а не в текстовом поле)

UPDATE: дубликат Получить курсор или текстовую позицию в пикселях для элемента ввода.

TL; DR - используйте невероятно легкую и надежную библиотеку компонентов textarea-caret-position, которая теперь поддерживает <input ype="text">. Демо на http://jsfiddle.net/dandv/aFPA7/


Есть ли способ узнать, где каретка находится внутри текстового поля HTML?

<input type='text' /> 

Я хотел бы позиционировать в пикселях (и менять) div в зависимости от положения каретки.

Примечание. Я не хочу знать позицию в символах или в <textarea>. Я хочу знать положение в пикселях в элементе <input>.

4b9b3361

Ответ 1

Используя невидимый элемент faux

Вы можете выполнить это, используя абсолютно позиционированное невидимое (используя visibility not display) faux-элемент, который имеет все те же свойства CSS, что и текстовое поле ввода (шрифты, левые границы и левое дополнение).

Этот очень короткий и понятный JSFiddle является отправной точкой для работы этого script.
Он работает в Chrome и Firefox как есть. И кажется, что он должен работать и в IE9 +.

Internet Explorer 8 (и вниз) будет нуждаться в дополнительном коде, чтобы получить позицию каретки от начала текста в текстовом поле ввода. Я даже добавил метр вверху, чтобы показать линию каждые 10 пикселей, чтобы вы могли видеть, правильно ли она измеряется. Имейте в виду, что строки находятся в положениях 1, 11, 21,... пикселя.

В этом примере он фактически принимает весь текст в текстовом поле до позиции каретки и помещает его в элемент faux, а затем измеряет его ширину в пикселях. Это позволяет вам смещаться слева от текстового поля.

Когда он копирует текст в faux-элемент, он также заменяет нормальные пробелы неразрывными, поэтому они фактически получают визуализацию иначе, если вы поместите каретку сразу после пробела, вы получите неправильную позицию:

var faux = $("#faux");
$("#test").on("keyup click focus", function(evt) {
    // get caret offset from start
    var off = this.selectionStart;

    // replace spaces with non-breaking space
    faux.text(this.value.substring(0, off).replace(/\s/g, "\u00a0"));
});​

Учтите, что размеры faux right

  • набивка
  • граница
  • Маржа

были удалены, чтобы получить правильное значение, иначе элемент будет слишком широк. Ящик элемента должен заканчиваться сразу после содержащегося в нем текста.

Положение каретки в пикселях от начала окна ввода затем легко получается из:

faux.outerWidth();

Проблема

Однако есть одна проблема. Я не уверен, как справляться с ситуацией, когда текст в текстовом поле прокручивается (когда слишком длинный), а карет не находится в самом конце текста, но где-то посередине... Если он в конце, то позиция каретки всегда на Максимальное возможное положение (ширина ввода меньше правых размеров - заполнение, граница, граница).

Я не уверен, возможно ли получить текстовое положение прокрутки в текстовом поле? Если вы сможете, то даже эту проблему можно решить. Но я не знаю о каком-либо решении этого вопроса...

Надеюсь, что это поможет.

Ответ 2

Разработав мой комментарий выше, я думаю, что следующее должно работать.

Чтобы показать принцип, я опустил форматирование, поэтому цвет элемента (id = "spacer" ) может потребоваться для #FFFFFE, возможно, некоторые пиксели ведущего пространства добавлены и т.д.... но каррет будет двигаться пропорционально сейчас - при условии, что id test и spacer используют один и тот же шрифт.

Конечно, мы не знаем расстояние в [px], как было задано, но мы можем размещать контент (в данном случае carret) полностью в соответствии с шириной пропорционального шрифта, поэтому, если это конечная цель (как упомянуто в строке 3 OP), тогда... voi lá!

<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <script type="text/javascript">
            function adjust()
            {
                document.getElementById('spacer').innerHTML=document.getElementById('test').value;
            }
        </script>
        <p>
            <input name="test" id="test" type="text" onkeyup="adjust()" /> Test <br />
            <span id="spacer"></span>^here
        </p>
    </body>
</html>

Update:

<span id="spacer" style="color: #FFFFFF"></span>

это сделает простую невидимую на белом фоне, но еще не помешает пользователю выделить текст разделителя, выбрав элемент span. Задача состоит в том, чтобы сделать разделитель невыбранным - там хорошее решение здесь

Ответ 4

Как насчет холста 2D? Он имеет API для рисования измерительного текста. Вы можете использовать это. Установите одинаковый шрифт, размер шрифта и вы сможете измерить ширину строки из текстового поля.

      $('body').append('<canvas id="textCanvas" width="100px" height="100px">I\'m sorry your browser does not support the HTML5 canvas element.</canvas>');
      var canvas = document.getElementById('textCanvas');
      var ctx = canvas.getContext('2d');
      ctx.measureText(text);
      var width = mes.width;

Я использовал такое решение для получения ширины некоторого текста, чтобы нарисовать его в WebGL. Я работал отлично, но я никогда не тестировал это, что произойдет, когда текст будет большим для контекста canvas, подумал, что это будет хорошо, потому что это API для измерения текста. Но Хо знает, что ты должен полностью проверить это!:)

Ответ 5

Вы можете использовать <span contenteditable="true"></span><input type="hidden" />. Таким образом вы можете использовать window.getSelection() с getRangeAt и getClientRects, чтобы получить позицию. Это должно работать с большинством современных браузеров, включая IE9 +:

function getCaret() {
    var caret = caret = {top: 0, height: 0},
        sel = window.getSelection();
    caret.top = 0;
    caret.height = 0;
    if(sel.rangeCount) {
        var range = sel.getRangeAt(0);          
        var rects = range.getClientRects();
        if (rects.length > 0) {
            caret.top = rects[0].top;
            caret.height = rects[0].height;
        } else {
            caret.top = range.startContainer.offsetTop - document.body.scrollTop;
            caret.height = range.startContainer.clientHeight;
        }
    }
    return caret;
}

(Имейте в виду, что проект, который я вытащил, ориентирован на Mobile Safari и использует один большой доступный контент, вам может потребоваться настроить его в соответствии с вашими потребностями. Это больше для демонстрационных целей, как получить координаты X и Y. )

Для IE8 и ниже IE имеет собственный API для получения той же информации.

Сложная часть - убедиться, что ваш элемент разрешает только обычный текст. В частности, с событием вставки. Когда диапазон теряет фокус (onblur), вы хотите скопировать содержимое в скрытое поле, чтобы оно могло быть опубликовано.

Ответ 6

heres рабочий пример http://jsfiddle.net/gPL3f/2/

чтобы найти положение каретки, я подсчитал буквы внутри входа и умножил это значение на размер 1 буквы.

и после этого переместил div в это место.

<html>
<head>
<style type="text/css">
body { font-size: 12px; line-height: 12px; font-family: arial;}
#box { width: 100px; height: 15px; position: absolute; top: 35px; left: 0px; background: pink;}
</style>
<script type="text/javascript" src="jquery-1.7.1.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var letter_size = 6;
$("input[type='text']").keyup(function(e) {
    move_size = $(this).val().length * letter_size;
    $('#box').css({'left': move_size+'px'}); 
});
});
</script>

</head>
<body>
<input type="text" />
<div id="box">
/ move 
</div>
</body>
<html>

ОБНОВЛЕНИЕ

$(document).ready(function(){
    var letter_size = 6;
    $("input[type='text']").keyup(function(e) {
        $('.hidden_for_width').text($(this).val());
        move_size = $('.hidden_for_width').width();
        $('#box').css({'left': move_size});
    });
});

добавлен скрытый контейнер, в который я вставляю значение из ввода. после этого я получаю ширину этого контейнера и перемещаю свой DIV соответственно

Ответ 7

function getCursorPosition (elem) {
  var pos = 0;  
  if (document.selection) {
    elem.focus ();
    var sele = document.selection.createRange();
    sele.moveStart('character', -elem.value.length);
    pos = sele.text.length;
  }
  else if (elem.selectionStart || elem.selectionStart == '0')
    pos = elem.selectionStart;
  return pos;
}​

getCursorPosition(document.getElementById('textbox1'))