Давайте рассмотрим различные события, сопутствующие обновлению данных.
Событие change срабатывает по окончании изменения элемента.
Для текстовых <input> это означает, что событие происходит при потере фокуса.
Пока мы печатаем в текстовом поле в примере ниже, событие не происходит. Но когда мы перемещаем фокус в другое место, например, нажимая на кнопку, то произойдёт событие change:
<input type="text" onchange="alert(this.value)">
<input type="button" value="Button">Для других элементов: select, input type=checkbox/radio событие запускается сразу после изменения значения:
<select onchange="alert(this.value)">
<option value="">Выберите что-нибудь</option>
<option value="1">Вариант 1</option>
<option value="2">Вариант 2</option>
<option value="3">Вариант 3</option>
</select>Событие input срабатывает каждый раз при изменении значения.
В отличие от событий клавиатуры, оно работает при любых изменениях значений, даже если они не связаны с клавиатурными действиями: вставка с помощью мыши или распознавание речи при диктовке текста.
Например:
<input type="text" id="input"> oninput: <span id="result"></span>
<script>
input.oninput = function() {
result.innerHTML = input.value;
};
</script>Если мы хотим обрабатывать каждое изменение в <input>, то это событие является лучшим выбором.
С другой стороны, событие input не происходит при вводе с клавиатуры или иных действиях, если при этом не меняется значение в текстовом поле, т.е. нажатия клавиш key:⇦, key:⇨ и подобных при фокусе на текстовом поле не вызовут это событие.
```smart header="Нельзя ничего предотвратить в oninput"
Событие `input` происходит после изменения значения.
Поэтому мы не можем использовать event.preventDefault() там -- уже слишком поздно, никакого эффекта не будет.
## События: cut, copy, paste
Эти события происходят при вырезании/копировании/вставке данных.
Они относятся к классу [ClipboardEvent](https://www.w3.org/TR/clipboard-apis/#clipboard-event-interfaces) и обеспечивают доступ к копируемым/вставляемым данным.
Мы также можем использовать `event.preventDefault()` для предотвращения действия по умолчанию, и в итоге ничего не скопируется/не вставится.
Например, код, приведённый ниже, предотвращает все `cut/copy/paste` события и показывает текст, который мы пытаемся вырезать/копировать/вставить:
```html autorun height=40 run
<input type="text" id="input">
<script>
input.onpaste = function(event) {
alert("paste: " + event.clipboardData.getData('text/plain'));
event.preventDefault();
};
input.oncut = input.oncopy = function(event) {
alert(event.type + '-' + document.getSelection());
event.preventDefault();
};
</script>
Обратите внимание: внутри обработчиков событий cut и copy вызов event.clipboardData.getData(...) возвращает пустую строку. Это потому, что технически данные ещё не находятся в буфере обмена. Если мы используем event.preventDefault() они вообще не будут скопированы.
Поэтому в приведённом выше примере используется document.getSelection() для получения выделенного текста. Более подробную информацию о выделении в документе можно найти в главе info:selection-range.
Возможно копирование/вставка не только текста, но и любых данных. Например, мы можем скопировать файл в файловом менеджере ОС и вставить его.
Это потому, что clipboardData реализует интерфейс DataTransfer, обычно используемый для перетаскивания и копирования/вставки. Сейчас это немного выходит за рамки нашего рассмотрения, но вы можете найти его методы в спецификации DataTransfer.
Кроме того, существует дополнительный асинхронный API для доступа к буферу обмена: navigator.clipboard. Подробнее -- в спецификации Clipboard API and events.
Буфер обмена работает глобально, на уровне ОС. Пользователь может переключаться между приложениями, копировать/вставлять различные данные, и страница браузера не должна всё это видеть.
Поэтому большинство браузеров разрешают беспрепятственный доступ к буферу обмена для чтения/записи только в рамках определённых действий пользователя, таких как копирование/вставка и т.д.
Запрещено генерировать "пользовательские" события буфера обмена с помощью dispatchEvent. И даже если нам удастся создать такое событие, спецификация чётко указывает, что такие "синтетические" события не должны предоставлять доступ к буферу обмена.
Даже если кто-то решит сохранить event.clipboardData в обработчике событий, а затем обратиться к нему позже -- это не сработает.
Повторим: event.clipboardData работает исключительно в контексте обработчиков событий, инициированных пользователем.
С другой стороны, navigator.clipboard -- более современный API, предназначенный для использования в любых сценариях. Он запрашивает разрешение пользователя, если это необходимо.
События изменения данных:
| Событие | Описание | Особенности |
|---|---|---|
change |
Значение было изменено. | Для текстовых полей срабатывает при потере фокуса. |
input |
Срабатывает при каждом изменении значения. | Запускается немедленно, в отличие от change. |
cut/copy/paste |
Действия по вырезанию/копированию/вставке. | Действие можно предотвратить. Свойство event.clipboardData предоставляет доступ на чтение/запись в буфер обмена. Также существует асинхронный API — navigator.clipboard. |