Wykrywanie zmiany Textarea

134

Jak wykryć zdarzenie zmiany w obszarze tekstowym za pomocą javascript?
Próbuję wykryć, ile znaków pozostało dostępnych podczas pisania.

Próbowałem użyć zdarzenia onchange, ale wydaje się, że działa tylko wtedy, gdy nie ma ostrości.

teepusink
źródło

Odpowiedzi:

98

Będziesz musiał użyć onkeyup i onchange do tego. Zmiana zapobiegnie wklejaniu menu kontekstowego, a onkeyup będzie uruchamiany przy każdym naciśnięciu klawisza.

Zobacz moją odpowiedź na temat Jak nałożyć maxlength na textArea dla przykładu kodu.

Josh Stodola
źródło
3
Chciałem tylko podkreślić to, co Josh już powiedział, że powinieneś używać do tego keyup, a nie keydown: wydaje się, że keydown jest wywoływany przed dokonaniem zmiany w obszarze tekstowym, więc użyjesz niewłaściwej długości (i nie Naprawdę nie wiem, jak bardzo jesteś: możesz pisać lub usuwać i możesz mieć zaznaczony tekst, co oznacza, że ​​jest to więcej niż tylko +/- 1).
brianmearns
67
Podaję tutaj -1, przepraszam! onkeyupto straszne zdarzenie dla wykrycia wejścia. Użyj oninputi onpropertychange(do obsługi IE).
Andy E
6
„Jedyny” problem NIEonchange jest wywoływany, gdy występuje wycinanie / wklejanie z menu kontekstowego.
Tom
4
O wiele bardziej responsywne jest użycie onkeydown i setTimeout, dzięki czemu uzyskujesz natychmiastowe wykrywanie zmian, zamiast czekać na zwolnienie klucza. Jeśli chcesz również przechwycić wycinanie i wklejanie, użyj zdarzeń wycinania i wklejania.
Kevin B,
1
Ostrzeżenie: onkeyup może spowodować kłopoty. Przykład: powiedzmy, że powinieneś coś zrobić tylko wtedy, gdy zmieniła się zawartość wejściowa. Jeśli założysz, że keyup zmieni dane wejściowe, to nie jest prawda. Skoncentruj się na wejściu. Użyj klawisza „tab”, aby przejść do następnego pola. Teraz użyj „shift + tab”, aby wrócić do wejścia. keyup uruchamia się, ale dane wejściowe nie zostały faktycznie zmienione przez użytkownika.
Zig Mandel
120

Jest rok 2012, nadeszła era post-PC, a my wciąż musimy zmagać się z czymś tak podstawowym jak to. To powinno być bardzo proste .

Dopóki to marzenie się nie spełni, oto najlepszy sposób na zrobienie tego, cross-browser: użyj kombinacji zdarzeń inputionpropertychange , na przykład:

var area = container.querySelector('textarea');
if (area.addEventListener) {
  area.addEventListener('input', function() {
    // event handling code for sane browsers
  }, false);
} else if (area.attachEvent) {
  area.attachEvent('onpropertychange', function() {
    // IE-specific event handling code
  });
}

inputWydarzenie zajmuje IE9 +, FF, Chrome, Opera i Safari , a onpropertychangedba o IE8 (działa również z IE6 i 7, ale istnieją pewne błędy).

Zaletą używania inputi onpropertychangejest to, że nie uruchamiają się niepotrzebnie (jak podczas naciskania klawiszy Ctrllub Shift); więc jeśli chcesz uruchomić stosunkowo kosztowną operację, gdy zmienia się zawartość obszaru tekstowego, to jest droga do zrobienia .

Teraz IE, jak zawsze, wykonuje połowiczną robotę, wspierając to: ani inputnie onpropertychangeuruchamia się w IE, gdy znaki są usuwane z obszaru tekstu. Jeśli więc chcesz zająć się usuwaniem znaków w IE, użyj keypress(w przeciwieństwie do używania keyup/ keydown, ponieważ uruchamiają się one tylko raz, nawet jeśli użytkownik naciśnie i przytrzyma klawisz).

Źródło: http://www.alistapart.com/articles/expanding-text-areas-made-elegant/

EDYCJA: Wydaje się, że nawet powyższe rozwiązanie nie jest idealne, jak słusznie wskazano w komentarzach: obecność addEventListenerwłaściwości w obszarze tekstowym nie oznacza, że ​​pracujesz z rozsądną przeglądarką; podobnie obecność attachEventdobra nie implikuje IE. Jeśli chcesz, aby Twój kod był naprawdę szczelny, powinieneś rozważyć zmianę tego. Zobacz komentarz Tim Down dla wskazówek.

Vicky Chijwani
źródło
1
To jest najlepsze podejście. Nie podoba mi się tutaj wnioskowanie (obsługa przeglądarki addEventListenernie oznacza obsługi inputzdarzenia lub odwrotnie); wykrywanie funkcji byłoby lepsze. Zobacz ten wpis na blogu, aby omówić ten temat.
Tim Down
Całkowicie zgadzam się z Timem w tej sprawie. oninputjak powinniśmy to zrobić, ale prawdopodobnie nie powinieneś używać go addEventListenerjako testu obsługi przeglądarki. +1 w każdym przypadku.
Ben D
1
Nie zgadzam się, wejście nie zajmie się IE9. Wytnij / Wklej za pomocą menu kontekstowego niestety jest również wejściem, podobnie jak Backspace. Nie zawracałem sobie głowy testowaniem, ale nie postawiłbym żadnych pieniędzy na zakład, że IE10 + naprawił ten problem.
Stefan Steiger,
1
@StefanSteiger, dlatego moja odpowiedź sugeruje również użycie keypresszdarzenia do obsługi tego przypadku w IE9 (i być może także późniejszych wersjach).
Vicky Chijwani
inputprocedurę obsługi zdarzeń można również zdefiniować, implementując .oninputwłaściwość obiektu.
uchwyt
21
  • W przypadku przeglądarki Google Chrome oninput będzie wystarczające (testowane w systemie Windows 7 w wersji 22.0.1229.94 m).
  • W IE 9 oninput przechwytuje wszystko oprócz wycięcia za pomocą menu kontekstowego i cofania.
  • W przypadku IE 8, oprócz oninput, wymagana jest opcja onpropertychange, aby złapać wklejanie.
  • W IE 9 + 8 onkeyup jest wymagany do przechwycenia backspace.
  • W IE 9 + 8 onmousemove to jedyny sposób, w jaki znalazłem wycinanie za pomocą menu kontekstowego

Nie testowano w przeglądarce Firefox.

    var isIE = /*@cc_on!@*/false; // Note: This line breaks closure compiler...

    function SuperDuperFunction() {
        // DoSomething
    }


    function SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally() {
        if(isIE) // For Chrome, oninput works as expected
            SuperDuperFunction();
    }

<textarea id="taSource"
          class="taSplitted"
          rows="4"
          cols="50"
          oninput="SuperDuperFunction();"
          onpropertychange="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onmousemove="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onkeyup="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();">
Test
</textarea>
Stefan Steiger
źródło
1
Niesamowite nazwy funkcji :)
Jonas Gröger
8

Wiem, że to nie jest dokładnie twoje pytanie, ale pomyślałem, że może się przydać. W przypadku niektórych aplikacji dobrze jest mieć funkcję zmiany uruchamianą nie za każdym razem, gdy naciśnięty zostanie klawisz. Można to osiągnąć za pomocą czegoś takiego:

var text = document.createElement('textarea');
text.rows = 10;
text.cols = 40;
document.body.appendChild(text);

text.onkeyup = function(){
var callcount = 0;
    var action = function(){
        alert('changed');
    }
    var delayAction = function(action, time){
        var expectcallcount = callcount;
        var delay = function(){
            if(callcount == expectcallcount){
                action();
            }
        }
        setTimeout(delay, time);
    }
    return function(eventtrigger){
        ++callcount;
        delayAction(action, 1200);
    }
}();

Działa to poprzez sprawdzenie, czy w pewnym okresie opóźnienia wystąpiło nowsze zdarzenie. Powodzenia!

user45743
źródło
1
+1 za opóźnione działanie „dławienia”! Używam czegoś podobnego w mojej aplikacji.
psulek
7

Wiem, że to pytanie było specyficzne dla JavaScript, jednak wydaje się, że nie ma dobrego, przejrzystego sposobu na ZAWSZE wykrycie, kiedy obszar tekstowy zmienia się we wszystkich obecnych przeglądarkach. Dowiedziałem się, że jquery zajął się tym za nas. Obsługuje nawet zmiany menu kontekstowego w obszarach tekstowych. Ta sama składnia jest używana niezależnie od typu wejścia.

    $('div.lawyerList').on('change','textarea',function(){
      // Change occurred so count chars...
    });

lub

    $('textarea').on('change',function(){
      // Change occurred so count chars...
    });
Tim Duncklee
źródło
4
Okazało się, że zdarzenie zmiany nie było bardziej spójne z jQuery niż ze zwykłym JS. Użyłem jQuery bind("input cut paste"...i działa jak urok - pisanie, wycinanie i wklejanie za pomocą klawiatury lub menu kontekstowego; nawet przeciągnij / upuść tekstu.
Lawrence Dol
2
Niestety FF nie odpala changezdarzenia dla textarea.
dma_k,
4

Możesz słuchać zdarzenia przy zmianie obszaru tekstowego i wprowadzać zmiany, jak chcesz. Oto jeden przykład.

const textArea = document.getElementById('my_text_area');
textArea.addEventListener('input', () => {
    var textLn =  textArea.value.length;
    if(textLn >= 100) {
        textArea.style.fontSize = '10pt';
    }
})
<html>
    <textarea id='my_text_area' rows="4" cols="50" style="font-size:40pt">
This text will change font after 100.
    </textarea>
</html>

Pankaj Manali
źródło
1
najlepsza odpowiedź, która jest najkrótsza
KetZoomer
1

Kluczowanie powinno wystarczyć, jeśli jest sparowane z atrybutem walidacji / wzorca wejścia HTML5. Dlatego utwórz wzorzec (wyrażenie regularne), aby sprawdzić poprawność danych wejściowych i działaj na podstawie statusu .checkValidity (). Coś jak poniżej może działać. W twoim przypadku chciałbyś, aby wyrażenie regularne odpowiadało długości. Moje rozwiązanie jest używane / demonstracyjne online tutaj .

<input type="text" pattern="[a-zA-Z]+" id="my-input">

var myInput = document.getElementById = "my-input";

myInput.addEventListener("keyup", function(){
  if(!this.checkValidity() || !this.value){
    submitButton.disabled = true;
  } else {
    submitButton.disabled = false;
  }
});
Ronnie Royston
źródło
0

Kod, którego użyłem dla IE 11 bez jQuery i tylko dla pojedynczego obszaru tekstowego:

JavaScript:

// Impede que o comentário tenha mais de num_max caracteres
var internalChange= 0; // important, prevent reenter
function limit_char(max)
{ 
    if (internalChange == 1)
    {
        internalChange= 0;
        return;
    }
    internalChange= 1;
    // <form> and <textarea> are the ID's of your form and textarea objects
    <form>.<textarea>.value= <form>.<textarea>.value.substring(0,max);
}

i html:

<TEXTAREA onpropertychange='limit_char(5)' ...
Rogério Silva
źródło
-1

Spróbuj tego. To proste, a ponieważ jest rok 2016, jestem pewien, że będzie działać na większości przeglądarek.

<textarea id="text" cols="50" rows="5" onkeyup="check()" maxlength="15"></textarea> 
<div><span id="spn"></span> characters left</div>

function check(){
    var string = document.getElementById("url").value
    var left = 15 - string.length;
    document.getElementById("spn").innerHTML = left;
}
domyślna
źródło
Więc otrzymujesz adres URL według identyfikatora, ale nie jest on wyświetlany w Twoim kodzie.
AbsoluteƵERØ
-9

Najlepszą rzeczą, jaką możesz zrobić, jest ustawienie funkcji, która ma być wywoływana w określonym czasie i ta funkcja, aby sprawdzić zawartość obszaru tekstowego.

self.setInterval('checkTextAreaValue()', 50);
I co
źródło
7
ankietowanie to bardzo zły pomysł. To po prostu zniszczy wydajność. Również, podobnie jak inne opublikowane, istnieje pewne rozwiązanie
Pier-Olivier Thibault,
2
To jest XXI wiek. Żadna przeglądarka nie powinna mieć problemów z obsługą porównania ciągów co 50 ms. Buforuj swoje selektory i jest to całkowicie akceptowalne rozwiązanie.
nieważność