DOM / style / addeventlistener

Прокрутити вниз

Введення в браузерні події: курси веброзробника

У цій статті розберемо DOM/style/addeventlistener. А більше дізнатися про програмування ви можете відвідавши курси веброзробника для дітей.

Подія – це сигнал про подію від браузера. Всі DOM-вузли подають такі сигнали (хоча події бувають не тільки в DOM).
Ознайоммось з DOM-подій, що часто використовуються:

Події миші:

  • click – відбувається, коли клацнули на елемент лівою кнопкою миші (на пристроях із сенсорними екранами воно відбувається при торканні).
  • contextmenu – відбувається, коли клікнули на елемент правою кнопкою миші.
  • mouseover / mouseout – коли миша наводиться на / залишає елемент.
  • mousedown / mouseup – коли натиснули / віджали кнопку миші на елементі.
  • mousemove – при русі миші.

Події на елементах керування:

  • submit – користувач відправив форму <form>.
  • focus – користувач фокусується на елементі, наприклад, натискає на <input>.

Клавіатурні події:

  • keydown і keyup – коли користувач натискає / відпускає клавішу.

Події документа:

  • DOMContentLoaded – коли HTML завантажений і оброблений, DOM документа повністю побудований і доступний.

CSS events:

  • transitionend – коли CSS-анімація завершена.

Існує багато інших подій. Курси веброзробника допоможуть дізнатися більше про DOM-події.

Обробники подій

Події можна призначити обробник, тобто функцію, яка спрацює, як тільки подія сталася.

Обробник сприяє тому, що JavaScript-код може реагувати на дії користувача. Для призначення оброблювача є кілька способів. І почнемо знайомство із найпростішого способу.

Використання атрибута HTML

Обробник може бути призначений прямо в розмітці, в атрибуті, який називається on<подія>.

Наприклад, щоб призначити обробник події click на елементі input, можна використовувати атрибут onclick, ось так:

<input value=”Натисніть мене” onclick=”alert(‘Клік!’)” type=”button”>

При натисканні мишкою на кнопці виконається код, вказаний в атрибуті onclick.

Зверніть увагу, для вмісту атрибуту onclick використовуються одинарні лапки, бо сам атрибут знаходиться в подвійних. Якщо ми забудемо про це і поставимо подвійні лапки всередині атрибуту, ось так: onclick=”alert(“Click!”)”, код не буде працювати.

Важливо: Атрибут HTML-тега – не найзручніше місце для написання великої кількості коду, тому краще створити окрему JavaScript-функцію та викликати її там.

Наступний приклад по кліку запускає функцію countRabbits():

<script>
function countRabbits() {
for(let i=1; i<=3; i++) {
alert(“Кролик номер” + i);
}
}
</script>

<input type=”button” onclick=”countRabbits()” value=”Вважати кроликів!”>

Як ми писали раніше, атрибут HTML-тега не чутливий до регістру, тому ONCLICK буде працювати так само як onClick і on CLICK … Але, як правило, атрибути пишуть в нижньому регістрі: onclick.

Використання властивості DOM-об’єкта

Можна призначати обробник, використовуючи властивість DOM-елементу on<подія>.

Наприклад, elem.onclick:

<input id=”elem” type=”button” value=”Натисніть мене!”>
<script>
elem.onclick = function() {
alert(‘Дякую’);
};
</script>

Якщо обробник заданий через атрибут, то браузер читає HTML-розмітку, створює нову функцію із вмісту атрибута та записує у властивість.

Цей спосіб, по суті, аналогічний до попереднього.

Обробник завжди зберігається як DOM-об’єкта, а атрибут – лише зі способів його ініціалізації.

Ці два приклади коду працюють однаково:

  1. Тільки HTML:

<input type=”button” onclick=”alert(‘Клік!’)” value=”Кнопка”>
2. HTML + JS:

<input type=”button” id=”button” value=”Кнопка”>
<script>
button.onclick = function() {
alert(‘Клік!’);
};
</script>

Бо в елемента DOM може бути тільки одна властивість з ім’ям onclick, то призначити більше одного оброблювача так не можна.

У прикладі нижче призначення через JavaScript перезапише обробник з атрибута:

<input type=”button” id=”elem” onclick=”alert(‘Було’)” value=”Натисніть мене”>
<script>
elem.onclick = function() { // перезапише існуючий обробник
alert(‘Стане’); // виведеться лише це
};
</script>

До речі, обробником можна призначити вже існуючу функцію:

function sayThanks() {
alert(‘Дякую!’);
}

elem.onclick = sayThanks;

Прибрати обробник можна призначенням elem.onclick = null.

Доступ до елемента через this

Усередині обробника події this посилається на поточний елемент, тобто на той, на якому, як кажуть, «висить» (тобто призначений) обробник.

У коді нижче button виводить свій вміст, використовуючи this.innerHTML:

<button onclick=”alert(this.innerHTML)”>Натисніть мене</button>

Часті помилки

 

Якщо ви новачок у роботі з подіями, варто звернути увагу на наступні моменти.

Функція повинна бути присвоєна як sayThanks, а не sayThanks().

// правильно
button.onclick = sayThanks;

// неправильно
button.onclick = sayThanks();

Якщо додати дужки, то sayThanks() – це вже виклик функції, результат якого (рівний undefined, тому що функція нічого не повертає) буде присвоєний onclick. Тож це не буде працювати.

…А ось у розмітці, на відміну від якості, дужки потрібні:

<input type=”button” id=”button” onclick=”sayThanks()”>

Цю різницю просто пояснити. При створенні обробника браузером з атрибута, він автоматично створює функцію з тілом зі значення атрибута: sayThanks().

Так що розмітка генерує таку властивість:

button.onclick = function() {
sayThanks(); //Вміст атрибуту
};

Використовуйте функції, а не рядки.

Призначення обробника рядком elem.onclick = “alert(1)” також спрацює. Це з міркувань сумісності, але робити так не рекомендується.

Не використовуйте setAttribute для обробників.

Такий виклик працювати не буде:

// При натисканні на body будуть помилки,
// атрибути завжди рядки, і функція стане рядком
document.body.setAttribute(‘onclick’, function() { alert(1) });

Реєстр DOM-властивості має значення.

Використовуйте elem.onclick, а не elem.ONCLICK, тому що DOM-властивості чутливі до регістру.

Курси веброзробника: addEventListener

Фундаментальний недолік описаних вище способів призначення обробника – неможливість повісити кілька обробників однією подія.

Наприклад, одна частина коду хоче при натисканні на кнопку робити її підсвіченою, а інша – видавати повідомлення.

Ми хочемо призначити два обробники для цього. Але нове DOM-властивість перезапише попереднє:

input.onclick = function() { alert(1); }
// …
input.onclick = function() { alert(2); } // замінить попередній обробник

Розробники стандартів досить давно це зрозуміли і запропонували альтернативний спосіб призначення обробників за допомогою спеціальних методів addEventListener і removeEventListener. Вони вільні від цього недоліку.

Синтаксис додавання обробника:

element.addEventListener(event, handler[, options]);
event
Ім’я події, наприклад, “click”.
handler
Посилання на функцію-обробник.
options

Додатковий об’єкт із властивостями:

  • once: якщо true, тоді обробник буде автоматично вилучений після виконання.
  • capture: фаза, на якій повинен спрацювати обробник, докладніше про це буде розказано в розділі Сплив і занурення. Так історично склалося, що options може бути false/true, це те ж саме, що {capture: false/true}.
  • passive: якщо true, то вказує, що обробник ніколи не викличе preventDefault(), докладніше про це буде розказано в розділі Дії браузера за замовчуванням.

Для видалення обробника слід використовувати removeEventListener:

element.removeEventListener(event, handler[, options]);
Вилучення вимагає саме ту ж функцію

Для видалення потрібно передати саме ту функцію-обробник, яка була призначена.

Отак не спрацює:

elem.addEventListener( “click” , () => alert(‘Дякую!’));
// ….
elem.removeEventListener( “click”, () => alert(‘Дякую!’));

Обробник нічого очікувати видалено, т.к. в removeEventListener передана не та ж функція, а інша, з однаковим кодом, але це не важливо.

Ось так вірно:

function handler() {
alert( ‘Дякую!’);
}

input.addEventListener(“click”, handler);
// ….
input.removeEventListener(“click”, handler);

Звернемо увагу – якщо функцію обробник не збережена будь-де, ми не зможемо її видалити. Немає методу, який дозволяє отримати з елемента обробники подій, призначені через addEventListener.

Метод addEventListener дозволяє додавати кілька обробників на одну подію одного елемента, наприклад:

<input id=”elem” type=”button” value=”Натисніть мене”/>

<script>
function handler1() {
alert(‘Дякую!’);
};

function handler2() {
alert(‘Дякую ще раз!’);
}

elem.onclick = () => alert(“Привіт”);
elem.addEventListener(“click”, handler1); // Спасибі!
elem.addEventListener(“click”, handler2); // Ще раз дякую!
</script>

Як видно з прикладу вище, можна одночасно призначати обробники через DOM-властивість і через addEventListener. Однак, щоб уникнути плутанини, рекомендується вибрати один спосіб.

Обробники деяких подій можна призначати тільки через addEventListener

Існують події, які не можна призначити через DOM-властивість, але можна через addEventListener.

Наприклад, така подія DOMContentLoaded, яка спрацьовує, коли завершено завантаження і побудова DOM документа.

document.onDOMContentLoaded = function() {
alert(“DOM побудований”); // не буде працювати
};
document.addEventListener(“DOMContentLoaded”, function() {
alert(“DOM побудований”); // а ось так спрацює
});

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

Об’єкт події

Щоб добре обробити подію, можуть знадобитися деталі того, що сталося. Не просто «клік» або «натискання клавіші», а також які координати вказівника миші, яка клавіша натиснута і так далі.

Коли відбувається подія, браузер створює об’єкт події, записує в нього деталі та передає його як аргумент функції-обробнику.

Приклад нижче демонструє отримання координат миші з події

<input type=”button” value
=”Натисніть мене” id=”elem”>

<script>
elem.onclick = function(event) {// вивести тип події, елемент та координати кліка
alert(event.type + “на” + event.currentTarget);
alert(“Координати:” + event.clientX + “:” + event.clientY);
};
</script>

Деякі властивості об’єкту event:

event.type
Тип події, в такому випадку “click”.
event.currentTarget
Елемент, у якому спрацював обробник. Значення – зазвичай таке ж, як і у this, але якщо обробник є функцією-стрілкою або за допомогою bind прив’язаний інший об’єкт як this, то ми можемо отримати елемент з event.currentTarget.
event.clientX/event.clientY
Координати курсору в момент кліку щодо вікна для подій миші.

Існує також і ряд інших властивостей, залежно від типу подій, які ми розберемо в подальших розділах.

Об’єкт події доступний і в HTML

При призначенні обробника в HTML теж можна використовувати об’єкт event, ось так:

<input type=”button” onclick=”alert(event.type)” value=”Тип події”>

Це можливо тому, що коли браузер з атрибута створює функцію-обробник, вона виглядає так: function(event) { alert(event.type) }. Тобто, її перший аргумент називається “event”, а тіло взяте з атрибута.

Об’єкт-обробник: handleEvent

Ми можемо призначити обробником не тільки функцію, але й об’єкт за допомогою addEventListener. У цьому випадку, коли відбувається подія, викликається метод об’єкта handleEvent.

Наприклад:

<button id=”elem”>Натисніть мене</button>

<script>
elem.addEventListener(‘click’, {
handleEvent(event) {
alert(event.type + “на” + event.currentTarget);
}
});
</script>

Як бачимо, якщо addEventListener отримує об’єкт як обробник, він викликає object.handleEvent(event), коли відбувається подія.

Ми також можемо використовувати клас для цього:

<button id=”elem”>Натисніть мене</button>

<script>
class Menu {
handleEvent(event) {
switch(event.type) {
case ‘mousedown’:
elem.innerHTML = “Натиснута кнопка миші”;
break;
case ‘mouseup’:
elem.innerHTML += “…і зажати.”;
break;
}
}
}

let menu = new Menu();
elem.addEventListener(‘mousedown’, menu);
elem.addEventListener(‘mouseup’, menu);
</script>

Тут той самий об’єкт обробляє обидві події. Зверніть увагу, ми повинні явно призначити обидва обробники через addEventListener. Тоді об’єкт menu отримуватиме події mousedown і mouseup, але не інші (не призначені) типи подій.

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

<button id=”elem”>Натисніть мене</button>

<script>
class Menu {
handleEvent(event) {
// mousedown -> onMousedown
let method = ‘on’ + event.type[0].toUpperCase() + event.type.slice(1);
this[method](event);
}

onMousedown() {
elem.innerHTML = “Кнопка миші натиснута”;
}

onMouseup() {
elem.innerHTML += “…і віджата.”;
}
}

let menu = new Menu();
elem.addEventListener(‘mousedown’, menu);
elem.addEventListener(‘mouseup’, menu);
</script>

Тепер обробка подій поділена методами, що спрощує підтримку коду.

Курси веброзробника для дітей – крок до успішного майбутнього.

Висновок:

Є три способи призначення обробників подій:

  1. Атрибут HTML: onclick=”…”.
  2. DOM-властивість: elem.onclick = function.
  3. Спеціальні методи: elem.addEventListener(event, handler[, phase]) для додавання, removeEventListener для видалення.

HTML-атрибути використовуються рідко тому, що JavaScript у HTML-тегу виглядає трохи інакше. До того ж багато коду там не напишеш.

DOM-властивості можна використовувати, але ми не можемо призначити більше одного обробника на один тип події. Найчастіше ці обмеження не критичні.

Останній спосіб найбільш гнучкий, проте потрібно писати найбільше коду. Є кілька типів подій, які працюють тільки через нього, наприклад transitionend і DOMContentLoaded. Також addEventListener підтримує об’єкти як обробників подій. У цьому випадку викликається метод об’єкта handleEvent.

Не важливо, як ви призначаєте обробник, він отримує об’єкт події першим аргументом. Цей об’єкт містить подробиці про те, що сталося.

Перевірити свої знання ви можете пройти тест вгорі сторінки. Пройшовши тест – обмінюйте сертифікат на коїни, а на подарунки. Бажаємо успіхів! А більше дізнатися про програмування ви можете відвідуючи курси веброзробника. Ми знаходимося на м. Академмістечко, м. Житомирська, також уроки проходять онлайн.