Uzyskaj pozycję kursora (w znakach) w polu tekstowym

211

Jak mogę uzyskać pozycję karetki z pola wejściowego?

Znalazłem kilka drobiazgów za pośrednictwem Google, ale nie ma kuloodpornego.

Zasadniczo idealna byłaby wtyczka jQuery, więc mogłem po prostu to zrobić

$("#myinput").caretPosition()
MarkB29
źródło
2
Spróbuj wyszukać „pozycję kursora”, która da ci o wiele więcej trafień, a także kilka tematów na ten temat na SO.
Alec
2
@CMS Znalezienie pozycji w sposób <input>jest łatwiejszy niż w przypadku <textarea>.
Andrew Mao,
1
@AndrewMao: i znacznie trudniej, jeśli tekst jest przewijany, a karetka jest wcześniejsza niż sizeznaki.
Dan Dascalescu
@alec: Zgadzam się, że wyszukiwanie kursora zamiast karetki może dać więcej rezultatów. Jak wskazano w innym miejscu, dowiedziałem się, że karetka jest bardziej odpowiednim terminem. Kursor reprezentuje lokalizację w czymkolwiek podczas gdy karetka reprezentuje lokalizację konkretnie w tekście.
Suncat2000

Odpowiedzi:

247

Łatwiejsza aktualizacja:

Użyj field.selectionStart przykładu w tej odpowiedzi .

Dzięki @commonSenseCode za zwrócenie na to uwagi.


Stara odpowiedź:

Znaleziono to rozwiązanie. Nie oparty na jquery, ale nie ma problemu z integracją go z jquery:

/*
** Returns the caret (cursor) position of the specified text field (oField).
** Return value range is 0-oField.value.length.
*/
function doGetCaretPosition (oField) {

  // Initialize
  var iCaretPos = 0;

  // IE Support
  if (document.selection) {

    // Set focus on the element
    oField.focus();

    // To get cursor position, get empty selection range
    var oSel = document.selection.createRange();

    // Move selection start to 0 position
    oSel.moveStart('character', -oField.value.length);

    // The caret position is selection length
    iCaretPos = oSel.text.length;
  }

  // Firefox support
  else if (oField.selectionStart || oField.selectionStart == '0')
    iCaretPos = oField.selectionDirection=='backward' ? oField.selectionStart : oField.selectionEnd;

  // Return results
  return iCaretPos;
}
bezmax
źródło
9
else if (oField.selectionStart || oField.selectionStart == '0')może byćelse if (typeof oField.selectionStart==='number')
user2428118
Jaka jest idea „oField.focus ()”? Działa dla mnie bez tej linii. Zachowaj ostrożność, jeśli użyjesz zdarzenia rozmycia na wejściu i wykonasz tę funkcję w wywołaniu zwrotnym.
Kirill Reznikov
Czy testujesz to na IE? To wszystko, jeśli sekcja jest wykonywana tylko w IE. W IE jest tylko globalny wybór, dlatego jest document.selection, nie, field.selectionczy coś. Ponadto w IE 7 można było wybrać (nie wiem, czy w 8+ jest to nadal możliwe), aby wybrać coś, a następnie TAB z pola bez utraty wyboru. W ten sposób, gdy tekst jest zaznaczony, ale pole nie jest ostre, document.selectionzwraca zaznaczenie zerowe. Dlatego, aby obejść ten błąd, musisz skoncentrować się na elemencie przed przeczytaniem document.selection.
bezmax,
zawsze dostaje 0 za chrome i firefox
Kaushik Thanki
117

Niezły, wielkie dzięki dla Maxa.

Zawarłem funkcjonalność w jego odpowiedzi w jQuery, jeśli ktoś chce z niej skorzystać.

(function($) {
    $.fn.getCursorPosition = function() {
        var input = this.get(0);
        if (!input) return; // No (input) element found
        if ('selectionStart' in input) {
            // Standard-compliant browsers
            return input.selectionStart;
        } else if (document.selection) {
            // IE
            input.focus();
            var sel = document.selection.createRange();
            var selLen = document.selection.createRange().text.length;
            sel.moveStart('character', -input.value.length);
            return sel.text.length - selLen;
        }
    }
})(jQuery);
MarkB29
źródło
3
Czy to nie input = $(this).get(0)to samo co input = this?
Mic
4
@Mic nie, nie we wtyczce jQuery. We wtyczce thisoznacza pełny pakiet. Jego kod jest jednak nadal błędny, tak powinno być this.get(0). Jego kod prawdopodobnie nadal działał, ponieważ ponowne zawijanie opakowanego zestawu nic nie robi.
Chev
1
To daje mi złe informacje. Podczas wprowadzania tekstu patrzyłem na pozycje kursora. Moje skrzypce to pokazuje: jsfiddle.net/fallenreaper/TSwyk
Fallenreaper
1
Firefox generuje NS_ERROR_FAILURE na input.selectionStart, gdy dane wejściowe są typu liczbowego, zawiń je w try {} catch {}?
niall.campbell
byłoby miło dla nowych pszczół, jeśli dodasz użycie funkcji
Muhammad Omer Aslam
98

BARDZO ŁATWE

Zaktualizowana odpowiedź

Użyj selectionStart, jest kompatybilny ze wszystkimi głównymi przeglądarkami .

document.getElementById('foobar').addEventListener('keyup', e => {
  console.log('Caret at: ', e.target.selectionStart)
})
<input id="foobar" />

Aktualizacja: Działa tylko wtedy, gdy żaden typ nie jest zdefiniowany lub type="text"na wejściu.

CommonSenseCode
źródło
2
Jeśli zmienię pozycję za pomocą myszy, nie zostanie to wydrukowane w konsoli. Czy istnieje sposób, aby to naprawić?
Eugene Barsky
3
@EugeneBarsky Wystarczy dodać nowy detektor zdarzeń dla zdarzenia click. Możesz sprawdzić .selectionStartwłaściwość w dowolnym momencie ( document.getElementById('foobar').selectionStart), nie musi ona znajdować się w detektorze zdarzeń.
JJJ
3
niesamowite, ale nie działa w przeglądarce Firefox lub Chrome, gdy typem danych jest liczba.
Adam R. Gray
26

Masz bardzo proste rozwiązanie . Wypróbuj następujący kod ze zweryfikowanym wynikiem -

<html>
<head>
<script>
    function f1(el) {
    var val = el.value;
    alert(val.slice(0, el.selectionStart).length);
}
</script>
</head>
<body>
<input type=text id=t1 value=abcd>
    <button onclick="f1(document.getElementById('t1'))">check position</button>
</body>
</html>

Daję ci fiddle_demo

Rajesh Paul
źródło
13
slicejest stosunkowo kosztowną operacją i nie dodaje nic do tego „rozwiązania” - el.selectionStartjest równoważne długości twojego plasterka; po prostu to zwróć. Co więcej, inne rozwiązania są bardziej skomplikowane, ponieważ obsługują inne przeglądarki, które nie obsługują selectionStart.
mpen
Zrezygnowałem z zadań, w których musiałem pracować z kodem o takich nazwach zmiennych jak ten.
Michael Scheper,
@Michael Scheper - Masz na myśli „el” dla elementu i „val” dla wartości? Są to dość powszechne ...
user2782001
6
@ user2782001: Błędnie napisałem - moją główną troską była nazwa funkcji. f1jest tak samo znaczący jak „user2782001”. 😉
Michael
16

Jest teraz ładna wtyczka do tego: The Caret Plugin

Następnie możesz uzyskać pozycję za pomocą $("#myTextBox").caret()lub ustawić ją$("#myTextBox").caret(position)

Jens Mikkelsen
źródło
1
wtyczka karetki wydaje się być przeznaczona dla elementów textarea, a nie danych wejściowych
schmidlop,
4
Cóż, mam to działa dla <input type = "text" id = "myTextBox" /> i używam powyższego kodu.
Jens Mikkelsen
14
   (function($) {
    $.fn.getCursorPosition = function() {
        var input = this.get(0);
        if (!input) return; // No (input) element found
        if (document.selection) {
            // IE
           input.focus();
        }
        return 'selectionStart' in input ? input.selectionStart:'' || Math.abs(document.selection.createRange().moveStart('character', -input.value.length));
     }
   })(jQuery);
Jerzy
źródło
10

Jest tu kilka dobrych odpowiedzi, ale myślę, że możesz uprościć swój kod i pominąć sprawdzanie inputElement.selectionStartpomocy: nie jest obsługiwane tylko w IE8 i wcześniejszych wersjach (patrz dokumentacja ), co stanowi mniej niż 1% bieżącego użycia przeglądarki .

var input = document.getElementById('myinput'); // or $('#myinput')[0]
var caretPos = input.selectionStart;

// and if you want to know if there is a selection or not inside your input:

if (input.selectionStart != input.selectionEnd)
{
    var selectionValue =
    input.value.substring(input.selectionStart, input.selectionEnd);
}
pmrotule
źródło
2

Być może potrzebujesz pozycji oprócz pozycji kursora. Oto prosta funkcja, nawet nie potrzebujesz jQuery:

function caretPosition(input) {
    var start = input[0].selectionStart,
        end = input[0].selectionEnd,
        diff = end - start;

    if (start >= 0 && start == end) {
        // do cursor position actions, example:
        console.log('Cursor Position: ' + start);
    } else if (start >= 0) {
        // do ranged select actions, example:
        console.log('Cursor Position: ' + start + ' to ' + end + ' (' + diff + ' selected chars)');
    }
}

Powiedzmy, że chcesz wywoływać go na wejściu, ilekroć się zmieni lub mysz zmieni pozycję kursora (w tym przypadku używamy jQuery .on()). Ze względu na wydajność dobrym pomysłem może być dodanie setTimeout()lub podkreślenie, _debounce()jeśli nadchodzą wydarzenia:

$('input[type="text"]').on('keyup mouseup mouseleave', function() {
    caretPosition($(this));
});

Oto skrzypce, jeśli chcesz to wypróbować: https://jsfiddle.net/Dhaupin/91189tq7/

dhaupin
źródło
0

const inpT = document.getElementById("text-box");
const inpC = document.getElementById("text-box-content");
// swch gets  inputs .
var swch;
// swch  if corsur is active in inputs defaulte is false .
var isSelect = false;

var crnselect;
// on focus
function setSwitch(e) {
  swch = e;
  isSelect = true;
  console.log("set Switch: " + isSelect);
}
// on click ev
function setEmoji() {
  if (isSelect) {
    console.log("emoji added :)");
    swch.value += ":)";
    swch.setSelectionRange(2,2 );
    isSelect = true;
  }

}
// on not selected on input . 
function onout() {
  // الافنت  اون كي اب 
  crnselect = inpC.selectionStart;
  
  // return input select not active after 200 ms .
  var len = swch.value.length;
  setTimeout(() => {
   (len == swch.value.length)? isSelect = false:isSelect = true;
  }, 200);
}
<h1> Try it !</h1>
    
		<input type="text" onfocus = "setSwitch(this)" onfocusout = "onout()" id="text-box" size="20" value="title">
		<input type="text" onfocus = "setSwitch(this)"  onfocusout = "onout()"  id="text-box-content" size="20" value="content">
<button onclick="setEmoji()">emogi :) </button>

Omar Bakhsh
źródło