Js сплив подій. JavaScript - Сплив події. Як же більшість із них працює

💖 Подобається?Поділися з друзями посиланням

Зараз ми з вами розберемо деякі просунуті речі під час роботи з об'єктом Event, а саме: спливання та перехоплення, а також делегування подій.

Сплив подій

Уявіть собі, що у вас є кілька вкладених один в одного блоків:

найвнутрішній блок

Коли ви клікаєте на самий внутрішній блок, подія onclick виникає спочатку в ньому, а потім спрацьовує в його батька, в батька його батька і так далі, поки не дійде те тега body і далі до тега html(потім до document і до window).

І це логічно, адже клацаючи на внутрішній блок, ви одночасно кликаєте на всі зовнішні.

Давайте переконаємося в цьому на наступному прикладі: у нас є 3 блоки, до кожного з них прив'язана подія onclick:

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

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

event.target

Нехай ми маємо два елементи: div і абзац p, що лежить усередині цього дива. Нехай onlick ми прив'язали до дива:

Коли ми кликаємо на це диво, ми можемо потрапити по абзацу, а можемо потрапити в місце, де цього абзацу немає.

Як таке може бути – подивіться на наступному прикладі: зелений колір- це наш див, а блакитний - наш абзац:

Якщо клікнути в зелену частину - ми клікнемо саме по диву, а якщо клікнути на блакитну частину - клік відбудеться спочатку абзацом, а потім уже дивом. Але оскільки onclick прив'язаний саме до дива - ми загалом присутність абзацу можемо і не помітити.

Однак, іноді нам хотілося б знати - клік стався безпосередньо за дивом або його нащадком абзацу. У цьому нам допоможе об'єкт Event та його властивість event.target – у ньому зберігається саме той елемент, у якому відбувся клік.

У наступному прикладі у нас є div, всередині нього лежить p, а всередині нього – span.

Давайте прив'яжемо подію onclick самому верхньому елементу(Диву) і будемо кликати на різні елементи: на div, на p, на span. За допомогою event.target отримаємо найнижчий елемент, в якому трапилася подія і виведемо його назву за допомогою tagName.

Якщо натиснути, наприклад, на span - то подія відловить наш div (адже саме до нього прив'язаний onclick), але в event.target лежатиме саме span :

Кликайте по різних блоках - ви побачите результат:

Припинення спливання

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

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

Клацніть на червоний блок - ви побачите результат:

Занурення

Окрім випливу подій є ще й занурення(По науковому стадія перехоплення). Це означає, що подія спочатку йде зверху донизу (стадія перехоплення), доходить до нашого елемента (стадія мети) і тільки потім починає спливати (стадія спливу).

Повісити обробник події з урахуванням стадії перехоплення можна лише за допомогою addEventListener. Для цього він має третій параметр: якщо він дорівнює true - подія спрацює на стадії перехоплення, а якщо false - на стадії спливання (це за замовчуванням):

Var green = document.getElementById("green"); green.addEventListener("click", func, true); function func(event) ( )

Стадію, на якій сталася подія, можна визначити за допомогою властивості event.eventPhase . Воно може приймати такі значення: 1 – стадія перехоплення, 2 – стадія мети, 3 – стадія спливання.

Вступ до делегування

Уявімо собі ситуацію: нехай у нас є ul з кількома li . До кожної li прив'язана наступна подія: після натискання на li їй в кінець додається "!".

Давайте реалізуємо описане:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
var li = document.querySelectorAll("#ul li"); //У циклі вішаємо функцію addSign на кожну li: for (var i = 0; i

Натисніть на li - ви побачите, як їм в кінець додається "!":

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5

Нехай тепер у нас також є кнопочка, натискання на яку в кінець ul додається нова li з текстом "пункт". Нас чекає сюрприз: прив'язана подія не працюватиме для нових li! Переконаємося у цьому:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Додати li

Натисніть на кнопку для додавання li, а потім на цю нову li - вона не зреагує:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Додати li

Для вирішення проблеми можна в момент створення нової li повісити на неї функцію addSign через addEventListener. Давайте реалізуємо це:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Додати li var li = document.querySelectorAll("#ul li"); for (var i = 0; i

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Додати li

Існує і другий спосіб оминути проблему – делегування подій. Давайте його розберемо.

Делегування подій

Суть делегування наступного: навісимо подію не так на кожну li, але в їхнього батька - на ul .

При цьому працездатність нашого скрипта повинна зберегтися: як і раніше, при кліку на li їй в кінець додаватиметься "!". Тільки подія у новому варіанті буде навішана на ul:

Var ul = document.getElementById("ul"); //Вішаємо подію на ul: ul.addEventListener("click", addSign); function addSign() ( )

Як ми це перевіримо: оскільки подія навішана на ul, то всередині функції ми можемо зловити li за допомогою event.target. Нагадаю, що таке event.target – це саме той тег, у якому стався клік, у нашому випадку це li.

Отже, ось вирішення нашого завдання через делегування:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5

Результат виконання коду:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5

При цьому наше рішення буде працювати автоматично навіть для нових li, адже подія навішена не на li, а на ul:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Додати li var ul = document.getElementById("ul"); ul.addEventListener("click", addSign); function addSign() ( event.target.innerHTML = event.target.innerHTML + "!"; ) //Реалізація кнопочки додавання нової li: var button = document.getElementById("button"); button.addEventListener("click", addLi); function addLi() ( var li = document.createElement("li"); li.innerHTML = "нова li"; ul.appendChild(li); )

Натисніть на кнопку для додавання li, а потім на цю нову li - вона зреагує:

  • пункт 1
  • пункт 2
  • пункт 3
  • пункт 4
  • пункт 5
Додати li

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

Універсальне делегування подій

Недолік нашого коду виявиться у тому випадку, коли всередині li будуть якісь вкладені теги. У нашому випадку нехай це будуть теги:

В цьому випадку натискання на i призведе до додавання знака окликув кінець тега i , а не тега li , як ми хотіли б (якщо натиснути на li поза курсивом - то все буде ок):

  • пункт курсив 1
  • пункт курсив 2
  • пункт курсив 3
  • пункт курсив 4
  • пункт курсив 5
var ul = document.getElementById("ul"); ul.addEventListener("click", addSign); function addSign() ( event.target.innerHTML = event.target.innerHTML + "!"; )

Натисніть на курсив – ви побачите як "!" додасться йому в кінець (натискання поза курсивом працюватиме нормально):

Проблема виправляється наступним чином (описаний спосіб не єдиний, але найпростіший): за допомогою методу closest знайдемо найближчу li, яка є батьком для event.target ось так: event.target.closest("li") .

Як це працює: якщо клік був на i, то в event.target лежить цей i, а в event.target.closest("li") - наша li, для якої має спрацювати подія.

Якщо ж клік був на самій li, то і в event.target, і в event.target.closest("li") лежатиме наша li.

Давайте перевіримо:

  • пункт курсив 1
  • пункт курсив 2
  • пункт курсив 3
  • пункт курсив 4
  • пункт курсив 5
var ul = document.getElementById("ul"); ul.addEventListener("click", function(event) ( var li = event.target.closest("li"); if (li) ( // перевіряємо, раптом li-батька взагалі немає li.innerHTML = li.innerHTML + "!";))));

Результат виконання коду:

Не важливо, яка глибина вкладеності: тег i може лежати в тезі b, а той у тезі span і тільки потім в li - це не має значення: конструкція event.target.closest("li") знайде батька з рівня вкладеності.

На цьому уроці ми познайомимося з таким поняттям як сплив події, а також розглянемо, як його можна перервати. Крім цього з'ясуємо, які ще етапи (фази) проходить подія, перш ніж почати виринати.

Випливання події

Якщо деякий елемент виникає подія, воно починає " спливати " , тобто. виникає у батька, потім у прабатька і т.д.

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

Сплив події (бульбашка) продемонструємо на наступному прикладі:

Заголовок

Деякий дуже важливий текст

Розділ

Деякий текст

Решта тексту

Напишемо невеликий скрипт, за допомогою якого додамо обробник події "click" для всіх елементів сторінки, а також для об'єктів document і window.

document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0; i< allElements.length; i++) { allElements[i].addEventListener("click",function() {console.log(this.tagName);},false); }; document.addEventListener("click",function() {console.log(this);},false); window.addEventListener("click",function() {console.log(this);},false); });

Створимо HTML-сторінку і вставимо в неї наведений вище HTML код. Сценарій, написаний мовою JavaScript, вставимо перед тегом body, що закриває. Після цього відкриємо щойно створену сторінку у веб-браузері, натисніть клавішу F12 і перейдемо в консоль. Тепер натиснемо лівою кнопкою мишкою в області, що належить елементу strong, і подивимося, як подія спливатиме.

Як перервати сплив події

Сплив події (бульбашка) можна перервати. У цьому випадку у вищестоящих (батьківських) елементів дана подія викликана не буде. Метод, який призначений для припинення спливання події (бульбашка) називається stopPropagation() .

Наприклад, змінимо наш наведений приклад таким чином, щоб подія не спливала вище body: document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0; i

Безперечно випливання - це дуже зручно та архітектурно прозоро. Не припиняйте його без потреби.

Отримання елемента, який викликав обробник

Для того, щоб отримати DOM-елемент (об'єкт), який викликав обробник події, необхідно використовувати ключове слово this . Дане ключове слово (this) доступне в обробнику лише в тому випадку, якщо Ви підписалися на подію за допомогою JavaScript.

Наприклад, виведемо в консоль id елемента, який викликав обробник події:

Var myP = document.getElementById("myP"); myP.addEventListener("click",function()( //отримаємо DOM-елемент, який викликав обробник події - this //отримаємо його id і виведемо його в консоль console.log(this.id); ));

Для отримання поточного елемента можна використовувати властивість currentTarget (event.currentTarget).

Етапи (фази) проходу події

Перед тим як події починає випливати (етап випливання), воно попередньо проходить ще 2 етапи:

  • 1 етап - це етап занурення до елемента, що згенерував подію. Тобто. цьому етапі відбувається рух зверху донизу, тобто. від об'єкта window до елемента. Також цей етап ще називають етапом перехоплення.
  • 2 етап - це етап досягнення мети, тобто. елемента (об'єкта), що згенерував подію.

З урахуванням всіх етапів, що проходять подію, виходить наступна картина:

Змінимо сценарій вищенаведеного прикладу таким чином:

Document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0; i

Третій параметр методів addEventListener та removeEventListener визначає етап, на якому буде спіймана подія. Якщо цей параметр має значення true , то подія перехоплюватиметься на стадії занурення (перехоплення) події. Якщо параметр має значення false , то подія перехоплюватиметься на етапі спливання. Для обробки події на самій меті можна використовувати метод addEventListener як зі значенням false , так і зі значенням true .

Увага: на стадії занурення (перехоплення) події можуть перехоплювати тільки обробники, додані за допомогою методу addEventListener() . Обробники, додані за допомогою інших способів (атрибут HTML або через JavaScript за допомогою властивості on [подія]) можуть перехоплювати події тільки на стадії спливання.

Отримання елемента, що згенерував подію

Щоб отримати цільової елемент, тобто. елемент, який згенерував подію, необхідно використовувати якість target (event.target).

Розглянемо наведений вище приклад, в якому змінимо вміст елемента script на наступне:

Document.addEventListener("DOMContentLoaded", function() ( var elementBody = document.body; elementBody.addEventListener("click",function()( console.log(this.tagName + " - елемент, який викликав обробник")); console .log(event.currentTarget.tagName + "- елемент, який викликав обробник"); console.log(event.target.tagName + "- елемент, який згенерував подію"); ),false);

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

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

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

Цей обробник для спрацює, якщо ви натисніть на вкладеному тегу або :

Клацніть на EM, спрацює обробник на DIV

Як бачите при натисканні на вкладеному елементі em спрацьовує обробник на div. Чому так відбувається? Читайте далі та дізнаєтесь.

Випливання

Отже основний принцип випливання:

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

Наприклад, нехай є 3 вкладені елементи FORM > DIV > P, з обробником події на кожному:

body * ( margin: 10px; border: 1px solid blue; ) FORM DIV

Сплив гарантує, що клік по внутрішньому елементу

Викличе обробник click (якщо він звичайно є) спочатку на самому

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

Доступ до цільового елементу event.target

Для того, щоб дізнатися, на якому саме елементі ми зловили ту чи іншу подію і існує метод event.target. (Про об'єкт event читайте).

  • event.target – це власне вихідний елемент, у якому і сталася подія.
  • this - це завжди поточний елемент, до якого дійшло спливання, і на ньому зараз виконується обробник.

Наприклад, якщо у вас встановлений лише один обробник form.onclick, то він і «зловить» усі кліки всередині форми. При цьому де б не був клік усередині - він все одно спливе до елемента, на якому і спрацює обробник.

При цьому:

  • this (=event.currentTarget) завжди буде сама форма, тому що обробник спрацював саме на ній.
  • event.target міститиме посилання на конкретний елемент усередині форми, найбільш вкладений, на якому стався клік.

У принципі це може збігатися з event.target якщо клікнули за формою і у формі більше немає жодних елементів.

Припинення спливання

Як правило сплив події йде прямо нагору і доходить до кореневого об'єкта window.

Але є можливість зупинити сплив на якомусь проміжному елементі.

Щоб зупинити спливання треба викликати метод event.stopPropagation().

Розглянемо приклад, при натисканні на кнопку обробник body.onclick не спрацює:

Клікни мене

Якщо елемент має кілька обробників на одну і ту ж саму подію, то навіть при припиненні спливання всі вони будуть виконані.

Таким чином, stopPropagation буде перешкоджати розповсюдженню події далі, але на елементі всі обробники відпрацюють, а далі на наступному елементі вже немає.

Щоб зупинити обробку на текщем елементі, браузери підтримують метод event.stopImmediatePropagation(). Цей метод не тільки запобігатиме спливанню, але й зупинить обробку подій на поточному елементі.

Занурення

У стандарті, крім «випливання» подій, є ще й «занурення».

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

Отже є 3 стадії проходу події:

  • Подія йде зверху донизу. Ця стадія називається "стадія перехоплення".
  • Подія досягла конкретного елемента. Це – «стадія мети».
  • Після всього подія починає спливати. Це – «стадія випливання».
  • У стандарті це продемонстровано так:

    Таким чином, при натисканні на TD подія подорожуватиме ланцюжком батьків спочатку вниз до елемента («занурюється»), а потім нагору («спливає»), по дорозі відповідно задіяні обробники.

    Вище я писав лише про сплив, тому що власне інші стадії, не використовуються і проходять непомітно для нас.

    Обробники нічого не знають про стадію перехоплення, а починають працювати зі спливання.

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

    • Аргумент true, то подія буде перехоплена дорогою вниз.
    • Аргумент false, то подія буде спіймана при спливанні.
    Приклади

    У прикладі на , ,

    Коштують ті ж обробники, що й раніше, але цього разу – на стадії занурення. Ну а щоб побачити перехоплення у дії, клацніть у ньому на елементі

    Обробники спрацюють у порядку «зверху-вниз»: FORM → DIV → P.

    JS-код тут такий:

    Var elems = document.querySelectorAll("form,div,p"); // на кожен елемент повісимо обробник на стадії перехоплення for (var i = 0; i< elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); }


    Ніхто вам не заважає призначити обробники для обох стадій, так:

    Var elems = document.querySelectorAll("form,div,p"); for (var i = 0; i< elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); elems[i].addEventListener("click", highlightThis, false); }

    Клацніть по внутрішньому елементу

    Щоб побачити порядок проходу події:
    Має бути FORM → DIV → P → P → DIV → FORM. Зауважимо, що елемент

    Братиме участь в обох стадіях.

    Підсумки
    • При настанні події – елемент, на якому сталася подія, позначається як event.target.
    • Подія спочатку рухається вниз від кореня документа до event.target, шляхом викликаючи обробники, поставлені через addEventListener(…., true).
    • Подія рухається від event.target вгору до початку документа, шляхом вона викликає обробники, поставлені через addEventListener(…., false).

    Кожен обробник матиме доступ до властивостей події:

    • event.target – найглибший елемент, на якому власне і сталася подія.
    • event.currentTarget (=this) - елемент, на якому в Наразіспрацював саморобець (до якого «дійшла» подія).
    • event.eventPhase - на якій фазі спрацював обробник події (занурення = 1, спливання = 3).

    Сплив можна зупинити викликом методу event.stopPropagation(), але робити це не рекомендується, оскільки подія може вам знадобиться для найнесподіваніших цілей.

    Events є actions або occurrences that happen in the system you are programming, which the system tells you about se you can respond to them in some way if desired. Для прикладу, якщо користувачеві клацніть кнопку на веб-сторінці, ви можете відповісти на те, що дія при відтворенні інформації box. У цьому матеріалі, ми розмовляємо про деякі важливі концепції, пов'язані з діяльністю, і показують, як вони працюють в браузерах. Це не буде exhaustive study; just what you need to know at this stage.

    Prerequisites: Objective:
    Базова комп'ютерна література, основна підтримка HTML і CSS, JavaScript перші кроки .
    Для того, щобпідтвердити важливу теорію заходів, як вони працюють в браузерах, і як показники можуть бути різними в різних програмних середовищах.
    A series of fortunate events

    Як mentioned above, events actions or occurrences that happen in the system you are programming - the system produces (or "fires") a signal of some kind when event occurs, and also provides a mechanismus by which some kind of action can автоматично такен (що є, деякий код керування) коли є можливі випадки. Для прикладу в аеропорту, коли хідний хід є чітким для плану, щоб зв'язатися, сигнал є комунікаційний до pilot, і як результат, вони посідають piloting the plane.

    У випадку з Web, Events є оголошено в браузері window, і tend to be attached to a specific item that resides in it - this might be a single element, set of elements, HTML document loaded in the current tab, or натисніть браузер window. Там є безліч різних типів заходів, які можуть спостерігатися, для прикладу:

    • Натисніть кнопку, щоб перейти до певного елемента або переміщатися в cursor над certain element.
    • User pressing key on the keyboard.
    • User resizing або closing браузері window.
    • A form being submitted.
    • A video being played, або paused, або finishing play.
    • An error occurring.

    Ви можете отримати від цього (і від сяйва в MDN Event reference), що є безліч речей, які можуть бути задоволені.

    У всіх наявних випадках є пункт handler , який є блоком коду (зазвичай JavaScript функція, що ви є програмістом створення), що буде йти, коли Event Fires. Коли такий блок code is defined to run in response to event firing, we say we are registering an event handler . Зверніть увагу, що якщо handlers є деякі названі еvent listeners - вони є найкращі дуже interchangeable для наших придбань, але стримано говорячи, вони працюють разом. Listener listens out for the event happening, і handler is the code that is run in response to it happening.

    Note : Web events не є частиною core JavaScript language - вони існують як частина APIs побудована в браузері.

    A simple example

    Let's look at a simple example to explain what we mean here. You"ve already seen events and event handlers used в багатьох examples in this course already, але let"s recap just to cement our knowledge. In the following example , we have a single , which when pressed, makes the background change to a random color:

    Change color

    Button (margin: 10px);

    The JavaScript looks like so:

    Const btn = document.querySelector("button"); function random(number) ( return Math.floor(Math.random() * (number+1)); ) btn.onclick = function() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol;

    У цьому коді, ми займаємося посиланням на клавішу всередині постійного зв'язку btn , використовуючи Document.querySelector() функцію. We also define a function that returns a random number. Ця третя частина code є event handler. Btn constant points до елемента, і цей тип об'єкта є числом випадків, які можуть бути на ньому, і там, якщо handlers available. Ви маєте можливість клацнути для того, щоб скористатися, натиснувши кнопку, щоб виконати позначку property до однієї anonymous функцій, що містить код, що генерується як RGB кольору, так і параметри background-color equal to it.

    Цей code is run whenever the click event fires on the element, that is, whenever a user clicks on it.

    The example output is as follows:

    It's not just web pages

    Інші ці ментальності в цьому пункті є те, що немає ніяких нюансів для JavaScript - максимальна програма англійської мови має деякий кінець будь-якого моделі, і в той спосіб, як моделі робіт порізні від JavaScript's way. pages differs from the event model for JavaScript as it is used in other environments.

    Inline event handlers - don't use these

    You might also see a pattern like this in your code:

    Press me function bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; )

    Сучасний метод реєстрації власників handlers заснований на веб-залучених мандрівниках HTML атрибутів (або в інших Events handlers ) як один показує вище - вказує значення є вірогідно JavaScript діаграми, коли можливі операції. Про те, як вказує на функцію, визначену в елементі на тій самій сторінці, але ти можеш усвідомити JavaScript безпосередньо всередині атрибуту, для прикладу:

    Press me

    Ви можете побачити HTML atributy equivalents для багатьох положень handler properties; Хоча, ви повинні використовувати це - вони вважаються недостатньою практикою. Це може скористатися зручним способом, щоб використовувати handler attribute if you are just doing something really quick, but they very quickly become unmanageable and inefficient.

    Для того, щоб запустити, це не приємно, щоб прослухати свій HTML і свій JavaScript, як це буде hard to parse - керувати своїм JavaScript all in one place better; if it is in a separate file you can apply it to multiple HTML documents.

    Будь-яка в одному файлі, в іншому випадку handlers не є хорошим ідеєю. One button is OK, but what if you had 100 buttons? You'd have to add 100 atributs to the file; it would very quickly turn into amaintenance nightmare. With JavaScript, you could easily add an event handler function to all the buttons on the page no matter how many therewere this:

    Const buttons = document.querySelectorAll("button"); for (let i = 0; i< buttons.length; i++) { buttons[i].onclick = bgChange; } buttons.forEach(function(button) { button.onclick = bgChange; });

    Note : Відокремлення вашого програмування логіки від вашого вмісту також робить ваш сайт більш приємним для пошуку.

    addEventListener() and removeEventListener()

    Новий тип поточного механізму є вказаним у документі об'єкта моделі (DOM) Level 2 Events Specification, які виконує браузерів з новою функцією - addEventListener() . Це функція в подібній мірі до того, що випливає технічна характеристика, але syntax є явно різним. We could rewrite our random color example to look like this:

    Const btn = document.querySelector("button"); function bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; ) btn.addEventListener("click", bgChange);

    У функцію addEventListener(), є specific two parameters - name of the event we want to register this handler for, and the code that comprise the handler function we want to run in response to it. Зверніть увагу, що це ідеально підходить для початку всіх повідомлень за адресоюEventListener() функція, в anonymous функції, як це:

    Btn.addEventListener("click", function() ( var rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body .style.backgroundColor = rndCol;));

    Цей mechanismus має певні переваги над попередніми технологіями, що розглянуті earlier. Для запуску, це функція counterpart, removeEventListener() , яка remove a previedly added listener. Для прикладу, це буде скористатися друкарем набір в перший код блоку в цьому розділі:

    Btn.removeEventListener("click", bgChange);

    Це не є важливим для простих, невеликих програм, але для великих, більше комплексних програм, які можуть викликати ефективність, щоб скористатися old unused event handlers. all you have to do is add or remove event handlers as appropriate.

    Second, ви можете також реєструвати низку handlers для того ж майстра. The following 2 handlers wouldn"t both be applied:

    MyElement.onclick = functionA; myElement.onclick = functionB;

    Second line overwrites the value of onclick set by the first line. This would work, however:

    MyElement.addEventListener("click", functionA); myElement.addEventListener("click", functionB);

    Both functions would now run when the element is clicked.

    У додатку, є номером інших потужних нюансів і можливостей доступних з цією функцією механізму. Вони мають велику кількість копій для цього сторінки, але якщо ви хочете, щоб читати на ньому, мати на увазі в addEventListener() і removeEventListener() reference pages.

    What mechanism should I use?

    З трьох механізмів, ви впевнено повинні використовувати HTML Event handler attributes - these are outdated, and bad practice, as mentioned above.

    Інші два є порівняно interchangeable, на рівні для прямих використання:

    • Event handler properties have less power and options, but better cross-browser compatibility (being supported as far back as Internet Explorer 8). Ви повинні спробувати запустити з цим, як ви вивчаєте.
    • DOM Level 2 Events (addEventListener() , etc.) є більш потужним, але може бути більше комплексу і не дуже добре supported (supported as back back as Internet Explorer 9). Ви повинні також experiment with these, and aim to use them where possible.

    Основні переваги трьох механізмів є те, що ви можете скористатися будь-яким handler code, якщо необхідно, використовуючи removeEventListener() , і ви можете скористатися множинними друкарями того ж типу, що потрібно. Для прикладу, ви можете Call addEventListener("click", function() ( ... )) на елементі multiple times, with different functions specified in the second argument. Це є неможливим з можливим handler properties because any subsequent attempts to set a property will overwrite earlier ones, e.g.:

    Element.onclick = function1; element.onclick = function2; etc.

    Note : Якщо ви збираєтеся підтримувати браузерів тільки через Internet Explorer 8 у вашій роботі, ви можете йти в різні параметри, як такі давні браузери використовувати різні моделі від нових браузеров. Але небагато, most JavaScript libraries (для example jQuery) мають вибудувати функції, що abstract away cross-browser differences. Don't worry про це те, що мусить на цьому етапі в вашій школі.

    Other event concepts

    У цьому розділі, ми можемо скористатися деякими розширеними концепціями, які є відповідними для дій. Це не важливо, щоб підтвердити ці поняття fully на цьому пункті, але вони мають право скористатися деякими кодами паперів.

    Event objects

    Певні часи в тому числі handler function, ви можете визначати параметри, які specified with name such as event , evt , or simply e . Це називається будь-яким об'єктом, і це автоматично проходить до списку handlers для забезпечення інших особливостей і інформації. Для прикладу, let's rewrite наш random color example again slightly:

    Function bgChange(e) ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; console.log(e); ) btn.addEventListener("click", bgChange);

    Тут ви можете бачити, що включно з можливим об'єктом, e , в функцію, і в функцію налаштування на background color style на e.target - який є button itself. Target property of event object always a reference to the element that the event has just occurred upon. Так, в цьому прикладі, ми беруть довжину background color на кнопці, не на сторінці.

    Note : Ви можете використовувати будь-яке ім'я як для того, щоб скористатися предметом - ви повинні скористатися назвою, що ви можете використати, щоб скористатися цією функцією. e / evt / event є найбільш загальним використанням для розробників тому, що вони є шорти і легко до remember. Це завжди добре, щоб бути - з вами, і з іншими, якщо можливо.

    e.target є неймовірно використовуваним, коли ви збираєтеся виконати той самий додаток handler на багато елементів і для того, щоб все в них, коли трапляються випадки на них. Ви можете, для прикладу, має set 16 tiles that disappear when they are clicked on. Це useful to always be able to just set the thing to disappear as e.target , інші не мають select it in some more difficult way. У наступному прикладі (див. useful-eventtarget.html для повного source code; also see it running live here), we create 16 elements using JavaScript. Ви можете вибрати все з використанням документа.

    Const divs = document.querySelectorAll("div"); for (let i = 0; i< divs.length; i++) { divs[i].onclick = function(e) { e.target.style.backgroundColor = bgChange(); } }

    Відповідь є наступними (натисніть поряд з ним - має fun):

    Hidden example Useful event target example div ( height: 100px; width: 25%; float: left; ) for (let i = 1; i
  • Pencil
  • Pen
  • Eraser

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

    Var toolbar = document.querySelector(".toolbar"); toolbar.addEventListener("click", function(e) ( var button = e.target; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList. remove("active"); ));
    Тепер ми маємо набагато чистіший код, і ми навіть позбулися циклів! Зауважте, що ми замінили e.currentTarget на e.target . Причина у тому, що ми обробляємо події іншому рівні.

    e.target - фактична мета події, те, куди вона пробирається через DOM, і звідки потім спливатиме.
    e.currentTarget – поточний елемент, який обробляє подію. У нашому випадку це ul.toolbar .

    Покращені спливаючі події В даний момент ми обробляємо будь-яке натискання на кожен елемент, який спливає через ul.toolbar, але наша умова перевірки є надто простою. Що сталося б, якби мали більш складний DOM, що включає іконки та елементи, які не були створені для того, щоб по них кликали?

    • Pencil
    • Pen
    • Eraser

    Упс! Тепер, коли ми натискаємо на li.separator або іконку, ми додаємо йому клас .active . Як мінімум, це недобре. Нам потрібен спосіб фільтрувати події так, щоб ми реагували на потрібний елемент.

    Створимо для цього невелику функцію-помічника:

    Var delegate = function(criteria, listener) ( return function(e) ( var el = e.target; do ( if (!criteria(el)) continue); return; ) while((el = el.parentNode)); ); );
    Наш помічник робить дві речі. По-перше, він обходить кожен елемент та її батьків і перевірять, чи задовольняють вони умові, переданому параметрі criteria . Якщо елемент задовольняє - помічник додає об'єкту події поле, зване delegateTarget , в якому зберігається елемент, який відповідає нашим умовам. І потім викликає оброблювач. Відповідно, якщо жоден елемент не задовольняє умову, жодного оброблювача не буде викликано.

    Ми можемо використовувати це так:

    Var toolbar = document.querySelector(".toolbar"); var buttonsFilter = function(elem) ( return elem.classList && elem.classList.contains("btn"); ); var buttonHandler = function(e) ( var button = e.delegateTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" );); toolbar.addEventListener("click", delegate(buttonsFilter, buttonHandler));
    Те, що лікар прописав: один обробник подій, прикріплений до одного елемента, який робить всю роботу. Але робить її лише для необхідних нам елементів. І він чудово реагує на додавання та видалення об'єктів з DOM.

    Підбиваючи підсумки Ми коротко розглянули основи реалізації делегування (обробки спливаючих) подій на чистий JavaScript. Це добре тим, що нам не потрібно генерувати та прикріплювати купу обробників для кожного елемента.

    Якби я хотів зробити з цього бібліотеку або використовувати код у розробці, я додав би пару речей:

    Функція-помічник для перевірки задоволення об'єкта критеріїв у більш уніфікованому та функціональному вигляді. Начебто:

    Var criteria = ( isElement: function(e) ( return e instanceof HTMLElement; ), hasClass: function(cls) ( return function(e) ( return criteria.isElement(e) && e.classList.contains(cls); ) ) // Більше критеріїв);
    Часткове використання помічника так само було б не зайвим:

    Var partialDelgate = function(criteria) ( return function(handler) ( return delgate(criteria, handler); ) );
    Оригінал статті: Understanding Delegated JavaScript Events
    (Від перекладача: мій перший, судіть суворо.)

    Щасливого кодингу!



    Розповісти друзям