10 KiB
Изменение: change, input, propertychange
На элементах формы происходят события клавиатуры и мыши, но есть и несколько других, особенных событий.
Событие change
Событие change происходит по окончании изменении значения элемента формы, когда это изменение зафиксировано.
Для текстовых элементов это означает, что событие произойдёт не при каждом вводе, а при потере фокуса.
Например, пока вы набираете что-то в текстовом поле ниже -- события нет. Но как только вы уведёте фокус на другой элемент, например, нажмёте кнопку -- произойдет событие onchange
.
<!--+ autorun height=40 -->
<input type="text" onchange="alert(this.value)">
<input type="button" value="Кнопка">
Для остальных же элементов: select
, input type=checkbox/radio
оно срабатывает сразу при выборе значения.
[warn header="Поздний onchange
в IE8-"]
В IE8- checkbox/radio
при изменении мышью не инициируют событие сразу, а ждут потери фокуса.
Для того, чтобы видеть изменения checkbox/radio
тут же -- в IE8- нужно повесить обработчик на событие click
(оно произойдет и при изменении значения с клавиатуры) или воспользоваться событием propertychange
, описанным далее.
[/warn]
Событие propertychange
Это событие происходит только в старых IE, до версии 11, при любом изменении свойства. Оно позволяет отлавливать изменение тут же и используется, преимущественно, для исправления ошибок в старых IE.
Если поставить его на checkbox
в IE8-, то получится "правильное" событие change
:
<!--+ autorun height=40 -->
<input type="checkbox"> Чекбокс с "onchange", работающим везде одинаково
<script>
var checkbox = document.body.children[0];
if("onpropertychange" in checkbox) {
// старый IE
*!*
checkbox.onpropertychange = function() {
// проверим имя изменённого свойства
if (event.propertyName == "checked") {
alert(checkbox.checked);
}
};
*/!*
} else {
// остальные браузеры
checkbox.onchange = function() {
alert(checkbox.checked);
};
}
</script>
Это событие также срабатывает при изменении значения текстового элемента, но в IE9 у него ошибка: оно не срабатывает при удалении символов.
Событие input
Событие input
срабатывает тут же при изменении значения текстового элемента и поддерживается всеми браузерами, кроме IE8-.
В IE9 оно поддерживается частично, а именно -- не возникает при удалении символов (как и onpropertychange
).
Пример использования (не работает в IE8-):
<!--+ autorun height=40 -->
<input type="text"> oninput: <span id="result"></span>
<script>
var input = document.body.children[0];
input.oninput = function() {
document.getElementById('result').innerHTML = input.value;
};
</script>
События cut, copy, paste
Эти события используются редко. Они происходят при вырезании/вставке/копировании значения.
К сожалению, кросс-браузерного способа получить данные, которые вставляются/копируются, не существует, поэтому их основное применение -- это отмена соответствующей операции.
Например, вот так:
<!--+ autorun height=40 -->
<input type="text" id="input"> event: <span id="result"></span>
<script>
input.oncut = input.oncopy = input.onpaste = function(event) {
result.innerHTML = event.type + ' ' + input.value;
return false;
};
</script>
Пример: поле с контролем СМС
Как видим, событий несколько и они взаимно дополняют друг друга.
Посмотрим, как их использовать, на примере.
Сделаем поле для СМС, рядом с которым должно показываться число символов, обновляющееся при каждом изменении поля.
Как такое реализовать?
Событие input
идеально решит задачу во всех браузерах, кроме IE9-. Собственно, если IE9- нам не нужен, то на этом можно и остановиться.
IE9-
В IE8- событие input
не поддерживается, но, как мы видели ранее, есть onpropertychange
, которое может заменить его.
Что же касается IE9 -- там поддерживаются и input
и onpropertychange
, но они оба не работают при удалении символов. Поэтому мы будем отслеживать удаление при помощи keyup
на [key Delete] и [key BackSpace] . А вот удаление командой "вырезать" из меню -- сможет отловить лишь oncut
.
Получается вот такая комбинация:
<!--+ autorun run height=60 -->
<input type="text" id="sms"> символов: <span id="result"></span>
<script>
function showCount() {
result.innerHTML = sms.value.length;
}
sms.onkeyup = sms.oninput = showCount;
sms.onpropertychange = function() {
if (event.propertyName == "value") showCount();
}
sms.oncut = function() {
setTimeout(showCount, 0); // на момент oncut значение еще старое
};
</script>
Здесь мы добавили вызов showCount
на все события, которые могут приводить к изменению значения. Да, иногда изменение будет обрабатываться несколько раз, но зато с гарантией. А лишние вызовы легко убрать, например, при помощи throttle
-декоратора, описанного в задаче .
Есть и совсем другой простой, но действенный вариант: через setInterval
регулярно проверять значение и, если оно слишком длинное, обрезать его.
Чтобы сэкономить ресурсы браузера, мы можем начинать отслеживание по onfocus
, а прекращать -- по onblur
, вот так:
<!--+ autorun height=60 -->
<input type="text" id="sms"> символов: <span id="result"></span>
<script>
var timerId;
sms.onfocus = function() {
var lastValue = sms.value;
timerId = setInterval(function() {
if (sms.value != lastValue) {
showCount();
lastValue = sms.value;
}
}, 20);
};
sms.onblur = function() {
clearInterval(timerId);
};
function showCount() {
result.innerHTML = sms.value.length;
}
</script>
Обратим внимание -- весь этот "танец с бубном" нужен только для поддержки IE8-, в которых не поддерживается oninput
и IE9, где oninput
не работает при удалении.
Итого
События изменения данных:
Событие | Описание | Особенности |
---|---|---|
`change` | Изменение значения любого элемента формы. Для текстовых элементов срабатывает при потере фокуса. | В IE8- на чекбоксах ждет потери фокуса, поэтому для мгновенной реакции ставят также `onclick`-обработчик или `onpropertychange`. |
`input` | Событие срабатывает только на текстовых элементах. Оно не ждет потери фокуса, в отличие от `change`. | В IE8- не поддерживается, в IE9 не работает при удалении символов. |
`propertychange` | Только для IE10-. Универсальное событие для отслеживания изменения свойств элементов. Имя изменённого свойства содержится в `event.propertyName`. Используют для мгновенной реакции на изменение значения в старых IE. | В IE9 не срабатывает при удалении символов. |
`cut/copy/paste` | Срабатывают при вставке/копировании/удалении текста. В них можно отменить действие браузера, и тогда вставке/копирования/удаления не произойдёт. | Вставляемое значение получить нельзя: на момент срабатывания события в элементе всё ещё *старое* значение, а новое недоступно. |
Ещё особенность: в IE8- события change
, propertychange
, cut
и аналогичные не всплывают. То есть, обработчики нужно назначать на сам элемент, без делегирования.