Pozycja karetki w pikselach w tekście typu wejściowego (nie textarea) [duplikat]

To pytanie ma już odpowiedź tutaj:

UPDATE : duplikat pobiera pozycję kursora lub tekstu w pikselach dla elementu wejściowego.

TL; DR - użyj niezwykle lekkiego i wytrzymałego textarea-caret-position komponent biblioteka, która teraz obsługuje również <input ype="text">. Demo na http://jsfiddle.net/dandv/aFPA7/


Czy istnieje sposób, aby wiedzieć, gdzie karetka znajduje się w polu tekstowym HTML?

<input type='text' /> 

Chciałbym umieścić w pikselach (i zmienić położenie) div w zależności od pozycji karetki.

Uwaga: nie chcę znać pozycji w znakach ani w <textarea>. Chcę znać pozycję w pikselach w <input> element.

Author: Zo72, 2012-11-12

7 answers

Korzystanie z niewidzialnego faux elementu

Możesz to osiągnąć, używając absolutnie niewidocznego (używając visibility, a nie display) sztucznego elementu, który ma wszystkie te same właściwości CSS, co pole tekstowe (czcionki, lewe obramowania i lewe wypełnienie).

Ten bardzo krótki i łatwy do zrozumienia JSFiddle jest punktem wyjścia do działania tego skryptu.
Działa w Chrome i Firefox tak jak jest. i wygląda na to, że powinno działać w IE9 + jako cóż.

Internet Explorer 8 (i w dół) będzie potrzebował dodatkowego kodu , aby uzyskać pozycję karetki od początku tekstu w polu tekstowym. Dodałem nawet miernik u góry, aby pokazać linię co 10 pikseli, dzięki czemu można zobaczyć, czy mierzy poprawnie, czy nie. Pamiętaj, że linie są na 1, 11, 21,... pozycji w pikselach.

Co ten przykład robi to faktycznie zabiera cały tekst w polu tekstowym do pozycji karetki i umieszcza go wewnątrz elementu faux, a następnie mierzy jego szerokość w pikseli. to przesunięcie od lewej strony pola tekstowego.

Kiedy kopiuje tekst do faux elementu, zastępuje również zwykłe spacje nietłukącymi się, więc są one renderowane w inny sposób, Jeśli ustawisz karetkę tuż za spacją, dostaniesz złą pozycję:

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"));
});​

Zwróć uwagę na właściwe wymiary

  • padding
  • border
  • margines

Zostały usunięte w celu uzyskania poprawnej wartości, w przeciwnym razie element byłby zbyt szeroki. Pole elementu musi kończyć się zaraz po tekście, który zawiera.

Pozycja Careta w pikselach od początku pola wejściowego jest łatwo uzyskiwana z:

faux.outerWidth();

Problem

Jest jednak jeden problem. Nie jestem pewien, jak poradzić sobie z sytuacją, gdy tekst w polu tekstowym jest przewijany (gdy jest zbyt długi), a karetka nie znajduje się na samym końcu tekstu, ale gdzieś pomiędzy... Jeśli jest na końcu, to pozycja karetki jest zawsze na maksymalnej możliwej pozycji (szerokość wejściowa mniej odpowiednich wymiarów - padding, border, margin).

Nie jestem pewien, czy możliwe jest uzyskanie pozycji przewijania tekstu w polu tekstowym? Jeśli możesz, to nawet ten problem można rozwiązać. Ale nie znam żadnego rozwiązania...

Mam nadzieję, że to pomoże.
 17
Author: Robert Koritnik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:35

Rozwijając mój komentarz powyżej, myślę, że następujące powinno zadziałać.

Aby pokazaÄ ‡ zasadÄ ™ pominÄ ™ Ĺ ' em formatowanie, wiÄ ™ c kolor elementu (ID="spacja") moĹźe byÄ ‡ ustawiony na #FFFFFE, moĹźe dodaÄ ‡ kilka pikseli spacji wiodÄ ... cej itp ... ale carret będzie teraz poruszać się proporcjonalnie-pod warunkiem, że test id i spacja używają tej samej czcionki.

Oczywiście nie znamy odległości w [px] zgodnie z pytaniem, ale jesteśmy w stanie pozycjonować treść (carret w tym case) w pełni zgodne z szerokością czcionki proporcjonalnej , więc jeśli jest to ostateczny cel (jak wspomniano w linii OP 3 ), to .... 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>

Spowoduje to, że ramka będzie niewidoczna na białym tle, ale nie uniemożliwia jeszcze podświetlenia tekstu ramki przez wybranie elementu span. Pozostawia zadanie uniezależnienia ramki dystansowej - jest dobre rozwiązanie tutaj

 4
Author: MikeD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:50
 2
Author: Jan Pfeifer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:27

A canvas 2D? Posiada API do rysowania tekstu pomiarowego. Przydałoby ci się. Ustaw tę samą czcionkę, rozmiar czcionki i powinieneś być w stanie zmierzyć szerokość łańcucha z pola tekstowego.

      $('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;

Użyłem tego rodzaju rozwiązania, aby uzyskać szerokość tekstu, aby narysować go w WebGL. Pracowałem dobrze, ale nigdy nie testowałem tego, co się stanie, gdy tekst jest duży dla kontekstu canvas, myślałem, że będzie dobrze, ponieważ jest to API do pomiaru tekstu. Ale ho wie, że powinieneś to sprawdzić. Wynocha! :)

 1
Author: n.podbielski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-19 18:35:38

Możesz użyć <span contenteditable="true"></span><input type="hidden" />. W ten sposób możesz użyć window.getSelection() z getRangeAt i getClientRects, Aby uzyskać pozycję. To powinno działać z większością nowoczesnych przeglądarek, w tym 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;
}

(pamiętaj, że projekt, z którego to wyciągnąłem, jest ukierunkowany na mobilne Safari i używa jednego dużego widoku contenteditable. Może być konieczne dostosowanie go do swoich potrzeb. To bardziej dla celów demonstracyjnych, jak uzyskać współrzędne X i Y.)

Dla IE8 i poniżej IE ma własnościowe API do uzyskania tego samego informacje.

Najtrudniejszą częścią jest upewnienie się, że twój element pozwala tylko na zwykły tekst. Szczególnie w przypadku wklejania. Gdy zakres straci focus (onblur), chcesz skopiować zawartość do ukrytego pola, aby można było ją opublikować.

 1
Author: Luke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-19 19:58:45

Heres przykład pracy http://jsfiddle.net/gPL3f/2/

Aby znaleźć pozycję karetki policzyłem litery wewnątrz wejścia i pomnożyłem tę wartość o wielkość 1 litery.

I po tym przeniósł div do tego miejsca.

<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>

UPDATE

$(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});
    });
});

Dodano Ukryty kontener w którym wstawiam wartość z wejścia . po tym dostaję szerokość tego kontenera i przesuwam odpowiednio mój DIV

 0
Author: Mihnea Belcin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-20 09:51:47
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'))
 -1
Author: Kir Ivlev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-12 16:42:05