Обнаружение изменения текстовой области

132

Как определить событие изменения в текстовом поле с помощью javascript?
Я пытаюсь определить, сколько символов осталось при вводе.

Я пробовал использовать событие onchange, но, похоже, это срабатывает только тогда, когда фокус отсутствует.

teepusink
источник

Ответы:

97

Вам нужно будет использовать onkeyup и onchange для этого. Onchange предотвратит вставку контекстного меню, и onkeyup будет срабатывать при каждом нажатии клавиши.

См. Мой ответ о том, как установить maxlength на textArea для примера кода.

Джош Стодола
источник
3
Просто хотел подчеркнуть то, что уже сказал Джош, что для этого вам следует использовать keyup, а не keydown: похоже, что keydown вызывается до того, как изменение фактически внесено в текстовое поле, поэтому вы будете использовать неправильную длину (а вы не Я действительно знаю, как вы себя чувствуете: может печатать или удалять, и может быть выделен текст, что означает больше, чем просто +/- 1).
brianmearns
65
Я ставлю здесь -1, извините! onkeyupэто ужасное событие для обнаружения ввода. Используйте oninputи onpropertychange(для поддержки IE).
Энди Э
6
«Только» проблема onchangeбудет НЕ срабатывает , когда возникает контекстное меню вырезать / вставить.
Tom
4
Намного более оперативно использовать onkeydown и setTimeout, чтобы вы получали мгновенное обнаружение изменений, а не дожидались выхода ключа. Если вам также нужно поймать вырезание и вставку, используйте события вырезания и вставки.
Kevin B
1
Предупреждение: onkeyup может вызвать проблемы. Пример: допустим, вы должны что-то делать, только если содержимое ввода изменилось. Если вы предполагаете, что клавиатура изменит ввод, это неверно. Сосредоточьтесь на вводе. Используйте вкладку, чтобы перейти к следующему полю. Теперь используйте «shift + tab», чтобы вернуться к вводу. keyup срабатывает, но ввод не был фактически изменен пользователем.
Зиг Мандель
117

Это 2012 год, наступила эра пост-ПК, и нам все еще приходится бороться с чем-то столь же простым, как это. Это должно быть очень просто .

До тех пор , пока эта мечта исполняется, вот лучший способ сделать это, кросс-браузер: используйте комбинацию из inputи onpropertychangeсобытий , как так:

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

inputМероприятие берет на IE9 +, FF, Chrome, Opera и Safari , и onpropertychangeзаботится о IE8 (он также работает с IE6 и 7, но есть некоторые ошибки).

Преимущество использования inputи в onpropertychangeтом, что они не срабатывают без необходимости (например, при нажатии клавиш Ctrlили Shift); так что, если вы хотите запустить относительно дорогостоящую операцию при изменении содержимого текстового поля, это правильный путь .

Теперь IE, как всегда, поддерживает это наполовину: в IE inputне onpropertychangeсрабатывают, когда символы удаляются из текстового поля. Поэтому, если вам нужно обработать удаление символов в IE, используйте keypress(в отличие от использования keyup/ keydown, потому что они срабатывают только один раз, даже если пользователь нажимает и удерживает клавишу).

Источник: http://www.alistapart.com/articles/expanding-text-areas-made-elegant/

РЕДАКТИРОВАТЬ: Кажется, что даже вышеуказанное решение не идеально, как правильно указано в комментариях: наличие addEventListenerсвойства в текстовом поле не означает, что вы работаете с нормальным браузером; аналогично наличие attachEventсвойства не подразумевает IE. Если вы хотите, чтобы ваш код был действительно герметичным, вам следует подумать об изменении этого. См . Комментарий Тима Дауна для указателей.

Вики Чижвани
источник
1
Это лучший подход. Мне не нравятся выводы здесь (поддержка браузером addEventListenerне подразумевает поддержку inputсобытия, и наоборот); обнаружение функции было бы лучше. См. Это сообщение в блоге для обсуждения этого.
Tim Down
Полностью согласен с Тимом в этом. oninputкак мы должны это сделать, но вы, вероятно, не должны использовать его в addEventListenerкачестве теста для поддержки браузера. +1 в любом случае.
Ben D
1
Не согласен, ввод не позаботится об IE9. Вырезать / вставить через контекстное меню, к сожалению, тоже можно, как и backspace. Я не стал тестировать, но не стал бы ставить на то, что IE10 + исправит эту проблему.
Стефан Штайгер
1
@StefanSteiger, поэтому мой ответ предлагает также использовать keypressсобытие для обработки этого случая в IE9 (и, возможно, в более поздних версиях).
Vicky Chijwani
inputСобытие Обработчик также может быть определен путем реализации .oninputсвойства объекта.
handle
20
  • Для Google-Chrome достаточно oninput (проверено в Windows 7 с версией 22.0.1229.94 m).
  • Для IE 9 oninput поймает все, кроме вырезания через контекстное меню и backspace.
  • Для IE 8 требуется onpropertychange для перехвата вставки в дополнение к oninput.
  • Для IE 9 + 8 требуется onkeyup для захвата backspace.
  • Для IE 9 + 8 onmousemove - единственный способ поймать резку через контекстное меню.

Не тестировалось в 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>
Стефан Штайгер
источник
1
Потрясающие имена функций :)
Йонас
8

Я знаю, что это не совсем ваш вопрос, но я подумал, что это может быть полезно. Для некоторых приложений хорошо, чтобы функция изменения срабатывала не каждый раз при нажатии клавиши. Этого можно добиться примерно так:

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

Это работает путем проверки того, возникло ли более недавнее событие в течение определенного периода задержки. Удачи!

user45743
источник
1
+1 за «дросселирование» отложенного действия! Я использую нечто подобное в своем приложении.
psulek 09
7

Я знаю, что этот вопрос был специфичен для JavaScript, однако, похоже, нет хорошего, чистого способа ВСЕГДА определять, когда текстовое поле изменяется во всех текущих браузерах. Я узнал, что jquery позаботился об этом за нас. Он даже обрабатывает изменения контекстного меню в текстовых областях. Один и тот же синтаксис используется независимо от типа ввода.

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

или

    $('textarea').on('change',function(){
      // Change occurred so count chars...
    });
Тим Данкли
источник
4
Я обнаружил, что событие изменения не более согласовано с jQuery, чем с простым JS. Я использовал jQuery, bind("input cut paste"...и он работает как шарм - ввод, вырезание и вставка с помощью клавиатуры или контекстного меню; даже перетаскивание текста.
Лоуренс Дол
2
К сожалению, FF не запускает changeсобытие для textarea.
dma_k 04
4

Вы можете прослушивать событие при изменении текстового поля и вносить изменения по своему усмотрению. Вот один пример.

(() => {
	const textArea = document.getElementById('my_text_area');
  textArea.addEventListener('input', () => {
    let 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>

Панкадж Манали
источник
1

Keyup должно хватить, если в паре с атрибутом проверки / шаблона ввода HTML5. Итак, создайте шаблон (регулярное выражение) для проверки ввода и воздействия на статус .checkValidity (). Что-то вроде ниже может сработать. В вашем случае вам нужно, чтобы регулярное выражение соответствовало длине. Мое решение используется / доступно для демонстрации онлайн здесь .

<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;
  }
});
Ронни Ройстон
источник
0

Код, который я использовал для IE 11 без jquery и только для одного текстового поля:

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

и HTML:

<TEXTAREA onpropertychange='limit_char(5)' ...
Рожерио Сильва
источник
-1

Попробуй это. Это просто, и с 2016 года я уверен, что он будет работать в большинстве браузеров.

<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;
}
дефолт
источник
Итак, вы получаете URL-адрес по идентификатору, но он не отображается в вашем коде.
AbsoluteƵERØ
-8

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

self.setInterval('checkTextAreaValue()', 50);
Ico
источник
7
опрос - очень плохая идея. Это просто разрушит производительность. Также, как и в других сообщениях, существует какое-то решение
Пьер-Оливье Тибо
2
Это 21 век. Ни у одного браузера не должно возникать проблем с обработкой сравнения строк каждые 50 мс. Кешируйте свои селекторы, и это вполне приемлемое решение.
Обнуление