Skip to content

Latest commit

 

History

History
113 lines (74 loc) · 8.81 KB

File metadata and controls

113 lines (74 loc) · 8.81 KB

События: change, input, cut, copy, paste

Давайте рассмотрим различные события, сопутствующие обновлению данных.

Событие: change

Событие 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 срабатывает каждый раз при изменении значения.

В отличие от событий клавиатуры, оно работает при любых изменениях значений, даже если они не связаны с клавиатурными действиями: вставка с помощью мыши или распознавание речи при диктовке текста.

Например:

<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.