16 липня 2023 р.

Події: change, input, cut, copy, paste

Давайте розглянемо події, які супроводжують оновлення даних.

Подія: change

Подія change спрацьовує після закінчення зміни елемента.

Для текстового поля це означає, що подія відбувається, коли втрачається фокус.

Наприклад, поки ми вводимо текст у текстовому полі нижче, події немає. Але коли ми перемістимо фокус кудись в інше місце, наприклад, натиснемо кнопку – відбудеться подія 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 запускається при будь-якій зміні значень, навіть тих, які не передбачають дії клавіатури: вставлення тексту за допомогою миші або використання розпізнавання мовлення для диктування тексту.

Наприклад:

<input type="text" id="input"> oninput: <span id="result"></span>
<script>
  input.oninput = function() {
    result.innerHTML = input.value;
  };
</script>

Якщо ми хочемо обробляти кожну модифікацію <input>, тоді ця подія є найкращим вибором.

З іншого боку, подія input не запускається під час введення з клавіатури та інших дій, які не передбачають зміну значення, напр. натискання клавіш зі стрілками .

Не можна нічому запобігти в oninput

Подія input відбувається після зміни значення.

Тож ми не можемо використовувати там event.preventDefault() – просто надто пізно, ефекту не буде.

Події: cut, copy, paste

Ці події відбуваються під час вирізання/копіювання/вставлення значення.

Вони належать до класу ClipboardEvent і надають доступ до даних, які вирізаються/копіюються/вставляються.

Ми можемо використовувати event.preventDefault(), щоб припинити дію, тоді нічого не буде скопійовано/вставлено.

Наприклад, наведений нижче код запобігає всім подіям cut/copy/paste і показує текст, який ми намагаємося вирізати/скопіювати/вставити:

<input type="text" id="input">
<script>
  input.onpaste = function(event) {
    alert("Вставити: " + 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(), щоб отримати виділений текст. Детальніше про вибір документів можна знайти в статті Selection і Range.

Можна копіювати/вставляти не тільки текст, а й все інше. Наприклад, ми можемо скопіювати файл у файловий менеджер ОС і вставити його.

Це тому, що clipboardData реалізує інтерфейс DataTransfer, який зазвичай використовується для перетягування та копіювання/вставлення. Зараз це трохи виходить за рамки наших можливостей, але ви можете знайти його методи в специфікації DataTransfer.

Крім того, існує додатковий асинхронний API для доступу до буфера обміну: navigator.clipboard. Детальніше про це в специфікації Clipboard API та події, не підтримується в Firefox.

Обмеження у сфері безпеки

Буфер обміну – це “глобальна” річ на рівні ОС. Користувач може перемикатися між різними програмами, копіювати/вставляти різні речі, і сторінка браузера не повинна бачити всього цього.

Тому більшість браузерів надають безперешкодний доступ для читання/запису до буфера обміну лише в рамках певних дій користувача, таких як копіювання/вставлення тощо.

Заборонено генерувати “користувацькі” події буфера обміну з dispatchEvent у всіх браузерах, крім Firefox. І навіть якщо нам вдасться відправити таку подію, у специфікації чітко зазначено, що такі “синтетичні” події не повинні надавати доступ до буфера обміну.

Навіть якщо хтось вирішить зберегти event.clipboardData в обробник подій, а потім отримати до нього доступ пізніше – це не спрацює.

Ще раз, event.clipboardData працює виключно в контексті ініційованих користувачем обробників подій.

З іншого боку, navigator.clipboard – це найновіший API, призначений для використання в будь-якому контексті. Він запитує дозвіл користувача, якщо потрібно.

Підсумки

Події зміни даних::

Подія Опис Особливості
change Значення було змінено. Для текстових полей спрацьовує при втраті фокусу.
input Спрацьовує при кожній зміні значення. Спрацьовує негайно, на відміну від change.
cut/copy/paste Дії при вирізанні/копіюванні/вставлянні. Дії можна запобігти. Властивість event.clipboardData надає доступ до буфера обміну. Усі браузери, крім Firefox, також підтримують navigator.clipboard.

Завдання

важливість: 5

Створіть інтерфейс, який дозволяє вводити суму банківського депозиту та відсоток, а потім обчислює, яким він буде через певні періоди часу.

Ось демо:

Будь-яка зміна введених даних має бути оброблена негайно.

Формула така:

// initial: початкова грошова сума
// interest: напр. 0,05 означає 5% на рік
// years: скільки років чекати
let result = Math.round(initial * (1 + interest) ** years);

Відкрити пісочницю для завдання.

Навчальна карта

Коментарі

прочитайте це, перш ніж коментувати…
  • Якщо у вас є пропозиції, щодо покращення підручника, будь ласка, створіть обговорення на GitHub або одразу створіть запит на злиття зі змінами.
  • Якщо ви не можете зрозуміти щось у статті, спробуйте покращити її, будь ласка.
  • Щоб вставити код, використовуйте тег <code>, для кількох рядків – обгорніть їх тегом <pre>, для понад 10 рядків – використовуйте пісочницю (plnkr, jsbin, codepen…)