1. Фази подій в JavaScript. Додаткова теорія (перейди за посиланням!!!) ⬇
2. Прослуховування подій в JavaScript(перейди за посиланням!!!) ⬇
Практично все, що ми робимо всередині програми, закінчується спрацюванням подій. Іноді наша програма буде запускати події автоматично, наприклад при завантаженні. В інших випадках воно буде запускати їх у вигляді реакції на наші дії, наш додаток постійно бомбардується подіями незалежно від того, хочемо ми, щоб вони спрацьовували, чи ні. Наше ж завдання — вказати додатку прослуховувати ті події, які нас цікавлять.
Вся робота щодо прослуховування потрібних подій повністю обробляється функцією, яка називається addEventListener. Ця функція завжди напоготові, тому може в потрібний час повідомити іншу частину додатки про те, що сталася певна подія. Використовується вона так: source.addEventListener(eventName, eventHandler, false);
Ми викликаємо addEventListener через елемент чи об'єкт, у якому хочемо прослуховувати події. Як правило, це буде елемент DOM, але ним також може бути document, window чи інший об'єкт, спеціально створений для запуску подій.
У вигляді першого аргументу для функції addEventListener ми вказуємо ім'я події, яку хочемо прослуховувати.
У другому аргументі потрібно вказати функцію, яка буде викликана, коли подія буде почута.
Останній аргумент складається з true чи false. Щоб повноцінно зрозуміти наслідки визначення того чи іншого значення, треба розібратися з темою «Сплив і занурення подій», яка саме розглядатиметься нижче.
Усередині функції addEventListener() ми вказуємо два параметри - ім'я події, для якої ми хочемо зареєструвати цей обробник, і код, що містить функцію обробника, яку ми хочемо запустити у відповідь. Зверніть увагу, що доцільно буде помістити весь код всередині функції addEventListener() в анонімну функцію.
Уявімо, що клацаємо по елементу buttonOne, при цьому запуститься подія кліка. Виникає питання звідки Саме буде запущено цю обставину. Воно (як майже кожна подія JavaScript) не виникає в елементі, з яким сталося взаємодія.


Починаючи з кореня, подія проходить шлях по вузлах DOM і зупиняється біля елемента, який його викликав, а саме buttonOne (також відомого як цільова подія)

Подія здійснює прямий шлях, але при цьому повідомляє кожен елемент на своєму шляху. Це означає, що якби ви прослуховували подію кліка в body, one_a, two або three_a, то спрацював би пов'язаний із ними обробник подій. Як тільки наша подія досягне своєї мети, вона не зупиниться і, продовжує рух своїми слідами назад до кореня.

Не має значення, де в DOM ініціюється подія. Воно завжди починає рух від кореня, спускається вниз до зустрічі з метою, а потім повертається до кореня. Цей шлях має офіційне визначення, тому давайте розглянемо його з цієї позиції
Коли на елементі відбувається подія, обробники спочатку спрацьовують на ньому, потім на його батькові, потім вище і так далі, вгору по ланцюжку предків.
Майже всі події спливають. Ключове слово у цій фразі – «майже». Наприклад, подія focus не спливає. Однак, варто розуміти, що це скоріше виняток, ніж правило, все-таки більшість подій спливає.
Завжди можна дізнатися, на якому конкретному елементі сталася подія. Глибокий елемент, який викликає подію, називається цільовим елементом, і він доступний через event.target.
Уявіть собі, що у вас є кілька вкладених один в одного блоків:

Натисніть на самий внутрішній рожевий блок - і ви побачите, як спочатку спрацює onclick рожевого блоку, потім блакитного, потім помаранчевого. Така поведінка називається спливанням подій - за аналогією зі спливанням бульбашки повітря з дна. Так само, як і пляшечку, наш клік по внутрішньому елементу ніби випливає нагору, щоразу спрацьовуючи на більш високих блоках.

Код із слухачем подій із третім параметром "false" спрацьовує також:

Всі події спливають до верху (до тега html, а потім до document, а потім до window). Іноді є потреба це спливання зупинити. Це може зробити будь-який елемент, через який спливає подія. Для цього в коді елемента потрібно викликати метод event.stopPropagation().
У наступному прикладі клік по жовтому блоку спрацює на ньому самому, потім на салатовому блоці і все-бузковий блок припиняє подальше спливання і бузковий блок вже ніяк не відреагує:


Далі в наступному прикладі клік по кожному блоку спрацює на ньому самому, припиняється подальше випливання:


event.target – це «цільовий» елемент, на якому сталася подія, в процесі випливання він незмінний. this - це «поточний» елемент, до якого дійшло спливання, на ньому зараз виконується обробник.
Наприклад, якщо стоїть лише один обробник form.onclick, він «зловить» всі кліки всередині форми. Де б не був клік усередині – він випливе до елемента form, на якому спрацює обробник.
При цьому всередині обробника form.onclick: this (=event.currentTarget) завжди буде елемент form, тому що обробник спрацював на ній. event.target міститиме посилання на конкретний елемент усередині форми, на якому стався клік.
Але будь-який проміжний обробник може вирішити, що подія повністю оброблена, і зупинити спливання.
Для цього потрібно викликати метод event.stopPropagation().

Частина, в якій ви ініціюєте подію і вона, починаючи з кореня, здійснює спуск вниз по DOM, називається фазою занурення події. Вона дуже рідко використовується в реальному коді, проте також може бути корисною.
Стандарт DOM Events описує 3 фази проходу події:
Отже, існують два варіанти значень опції capture:
Якщо ви не вкажете третій аргумент, то стандартною поведінкою буде прослуховування вашої події під час фази висхідного ланцюжка. Це еквівалентно передачі як аргумент помилкового значення.
Продовжимо розглядати приклад 1:

Тепер напишемо три обробники і призначимо їх кожному блоку за допомогою addEventListener:

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

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


Отримуємо спрацювання одразу трьох обробників.


Щоб упіймати подію на стадії занурення, потрібно використовувати третій аргумент capture ось так:


Створимо таку сторінку:

Розмітка виглядає так:

CSS виглядає так:


Пишемо скрипт:

Отже в коді вище ми включаємо об'єкт події event у функцію, а функції — налаштування стилю фону для event.target, який є кнопкою, текстовим полем, div, form(той елемент, у якому натискаємо). Властивість об'єкта події target завжди є посиланням на елемент, з яким щойно відбулася подія.
Тут обробники навішуються на кожен елемент у документі, щоб побачити, в якому порядку вони викликаються в міру проходу події.
При настанні події – найглибше вкладений елемент, на якому вона відбулася, позначається як «цільова» (event.target).
Потім подія спочатку рухається вниз від кореня документа до event.target, шляхом викликаючи обробники, поставлені через addEventListener(...., true), де true - це скорочення для {capture: true}.
Далі обробники викликаються на цільовому елементі.
Далі подія рухається від event.target вгору до кореня документа, шляхом викликаючи обробники, поставлені через on Кожен обробник має доступ до властивостей події event:
Будь-який обробник може зупинити подію викликом event.stopPropagation(), але робити це не рекомендується, так як надалі ця подія може знадобитися, іноді для несподіваних речей.
У сучасній розробці стадія занурення використовується дуже рідко, зазвичай події обробляються під час випливання.
Якщо закоментувати у скрипті код, позначений зеленою рамочкою, завжди буде спрацьовувати обробник події для форми.
Інколи потрібно видаляти слухача подій з елемента. Робиться
це за допомогою найлютішого ворога addEventListener функції removeEventListener:
something.removeEventListener(eventName, eventHandler, false);
Як видно з прикладу, ця функція отримує точно такі ж типи
аргументів, як і функція addEventListener. Причина цього проста. Коли
ми прослуховуємо подію в елементі або об'єкті, JavaScript використовує
eventName, eventHandler і значення true/false, щоб упізнати слухача подій. Щоб видалити цього слухача подій, нам потрібно вказати
точно такі ж аргументи. Ось приклад:
document.addEventListener("click", changeColor, false);
document.removeEventListener("click", changeColor, false);
function changeColor() {
document.body.style.backgroundColor = "#FFC926";
}
Слухач подій, якого ми додали у першому рядку, повністю
нейтралізовано викликом removeEventListener у виділеному другому рядку.
Якщо виклик removeEventListener використовує аргументи, відмінні від
зазначених у відповідному виклику addEventListener, то його зусилля
будуть проігноровані та прослуховування продовжиться.
По небу літає пташка.Користувач ловить її мишкою. Якщо спіймав, картинка з пташкою змінюється на кота, на траву.
Пізніше, коли розглядатимемо інші події миші, ми ще раз згадаємо цей приклад, але поки що нас цікавить тільки
ситуація, коли потрібно видаляти слухача подій з елемента.




ВИДАЛЕННЯ СЛУХАЧА ПОДІЙ
Приклад 3

