Home

Events. Поширення подій та оптимізація

Зміст

  1. Поширення подій
  2. Делегування подій
  3. Throttle і Debounce (Скрол)
  4. Відкладене завантаження

Поширення подій

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

Під час настання події, вона проходить через три обов'язкові фази:

  • Capturing phase (занурення) - подія починається на window і тоне (проходить через усі елементи-предки) до найглибшого цільового елемента, на якому відбулася дія, наприклад, клік.
  • Target phase (таргетинг) - подія дійшла до цільового елемента. Цей етап містить тільки повідомлення елемента про те, що на ньому відбулася дія
  • Bubbling phase (спливання) - кінцева фаза, подія спливає від найглибшого, цільового елемента, через усі елементи-предки до window.

Спливання подій

codepen

Спливають майже всі події, наприклад, події focus і blur не спливають, тому існують їх спливаючі аналоги - focusin і focusout.

Властивість event.target

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

.event.target - це посилання на вихідний елемент, на якому відбулася подія, в процесі спливання вона - незмінна.

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

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

    codepen
    const parent = document.querySelector("#parent");

    parent.addEventListener("click", (event) => {
      console.log("event.target: ", event.target);
      console.log("event.currentTarget: ", event.currentTarget);
    });

Припинення спливання stopPropagation()

Зазвичай, подія буде спливати вгору до елемента window, викликаючи усі обробники на своєму шляху. Але будь-який проміжний обробник може вирішити, що подія повністю оброблена і зупинити спливання, викликавши метод stopPropagation()

    codepen
    const parent = document.querySelector("#parent");
    const child = document.querySelector("#child");
    const descendant = document.querySelector("#descendant");

    parent.addEventListener("click", () => {
      alert(
        "Parent click handler!"
      );
    });

    child.addEventListener("click", () => {
      alert(
        "Child click handler!"
      );
    });

    descendant.addEventListener("click", (event) => {
      event.stopPropagation();
      alert("Descendant click handler");
    });

stopImmediatePropagation() Якщо елемент має декілька обробників на одну подію, то, навіть у разі припинення спливання, усі вони будуть виконані. Тобто метод stopPropagation() тільки перешкоджає просуванню події далі. Якщо необхідно повністю зупинити обробку події, використовується метод stopImmediatePropagation(). Він не тільки запобігає спливанню, але й зупиняє обробку подій на поточному елементі.

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

Спливання дозволяє реалізувати один із найкорисніших прийомів - делегування подій (event delegation). Він полягає у тому, що, якщо є група елементів, події яких потрібно обробляти однаково, то додається один обробник на їх загального предка, замість того, щоб додавати обробник до кожного елемента. Використовуючи властивість event.target, можна отримати посилання на цільовий елемент, зрозуміти, на якому саме дочірньому елементі відбулася подія, і обробити її.

делегування зводиться до трьох простих кроків.

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

Палітра кольорів

Будемо створювати палітру кольорів з можливістю вибрати колір по кліку і відображенням обраного кольору

    codepen        
    p class="output"Selected color: /p
    div class="color-palette"/div
                

Дивись js код

Selected color: -

    function selectColor(event) {
        if (event.target.nodeName !== "BUTTON") {
          return;
        }
        const selectedColor = event.target.dataset.color;
    } 

CDNjs

Lodash

Як пыдключити?

  • Заходимо сюди cdn lodash
  • копіюємо тег як на фото та вставляємо перед тегом боді як зроблено тут
  • У js файлі не імпортуємо а відразу користуємось
    const result = _.add(2, 3);
    console.log(result); // 5 
lodash

cdn library

Підтримка браузерів

Throttle і Debounce

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

Scroll me

Number of scroll events

0

Throttle і Debounce - це два схожих, але різних за поведінкою прийоми, що дозволяють контролювати кількість разів, яку ми дозволяємо виконувати функції з часом. Використовуємо їх реалізацію з бібліотеки Lodash.

Throttle

дозволяє викликати функцію не частіше одного разу за N мілісекунд, гарантуючи її регулярне виконання.

    document.addEventListener(
      "scroll",
      _.throttle(() => {
        console.log("Scroll handler call every 300ms");
      }, 300)
    );

Scroll me

Number of scroll events

0

Debounce

Прийом debounce гарантує, що функція буде викликана лише у тому разі, якщо між подіями буде пауза N мілісекунд. Наприклад, доки користувач скролить сторінку функція не буде викликана, але щойно він перестав скролити, функція буде викликана через 300 мілісекунд.

Scroll me

Number of scroll events

0

За замовчуванням метод debounce працює у режимі, коли функція викликається через N мілісекунд після паузи між потоками подій. Цей режим називається trailing edge (в кінці). Існують завдання, коли функцію потрібно викликати відразу під час настання першої події в потоці, а потім ігнорувати усі наступні події до паузи між ними, наприклад, - 300 мілісекунд. На старті наступного потоку подій ця поведінка повторюється. Такий режим називається leading edge (на початку).

Методу debounce бібліотеки Lodash можна передати необов'язковий третій аргумент - об'єкт параметрів, який містить дві властивості leading (за замовчуванням false) і trailing (за замовчуванням true). Ці налаштування змінюють режим і вказують, чи повинна функція запускатися на початку потоку подій або в кінці після паузи.

    codepen
    document.addEventListener(
      "scroll",
      _.debounce(
        () => {
          console.log("Scroll call on every event start");
        }, 300,
        {
          leading: true,
          trailing: false,
        }
      )
    );

Відкладене завантаження

Веб-сторінки містять велику кількість зображень, які збільшують розмір сторінок і впливають на швидкість їх завантаження. Більшість зображень знаходяться за межами першого екрану (за кадром, below the fold), тому користувач побачить їх тільки після прокручування сторінки.

Відкладене завантаження (lazy-loading) - це прийом, який відкладає завантаження некритичних ресурсів під час завантаження сторінки. Замість цього, ці некритичні ресурси завантажуються лише у разі потреби.

Атрибут loading​

    img src="my-image.jpg" loading="lazy" alt="Image description" /

Підтримує три значення:

  • lazy - браузер виконає відкладене завантаження зображення.
  • eager - зображення буде завантажене за першої нагоди, тобто без відкладеного завантаження.
  • auto - браузер сам визначає - виконувати відкладене завантаження чи ні.

codepen

Відкрийте вкладку Network в інструментах розробника і виберіть фільтр Img, щоб відображалось лише завантаження зображень. Після цього прокручуйте приклад і спостерігайте як будуть довантажуватися закадрові зображення котів. Браузери, що підтримують атрибут loading, будуть завантажувати зображення відкладено, а браузери без підтримки - завантажать усі зображення відразу.

Бібліотека lazysizes​

Щоб забезпечити кросбраузерність, тобто сумісність зі старішими браузерами, або такими, які ще не підтримують це нативно, можна використовувати ряд існуючих JavaScript бібліотек. Одні з найпопулярніших - це lazysizes, vanilla-lazyload і lozad.js. Вибір бібліотеки зводиться до набору можливостей і особистих вподобань. Ми розберемо бібліотеку .

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

Бібліотека lazysizes самоініціалізується при завантаженні на сторінку. Тобто для базового використання в JavaScript нічого робити непотрібно. Повний список її можливостей наведений в документації.

Усім зображенням, які необхідно завантажувати відкладено, задаємо клас lazyload і замінюємо атрибут src на data-src. Це необхідно бібліотеці lazysizes для правильної роботи.

    <img class="lazyload" data-src="path/to/my-image.jpg" 
        alt="Generic alt" />

Доки зображення завантажується можна показувати заповнювач низької якості. Ця техніка називається LQIP (Low Quality Image Placeholder). Існує багато варіантів реалізації LQIP, але для початку достатньо буде показувати один стандартний заповнювач, замість усіх зображень. Для цього додаємо атрибут src, значенням якого буде посилання на це зображення-заповнювач. index.html

    <img
      class="lazyload"
      src="path/to/lqip-placeholder.jpg"
      data-src="path/to/my-image.jpg"
      alt="Generic alt"
    / >

Коли зображення було завантажене, бібліотека lazysizes додає елементу клас lazyloaded. Це можна використовувати для застосування CSS-ефектів в момент завантаження зображення. styles.css

    .blur-up {
        filter: blur(5px);
        transition: filter 400ms;
      }
      
      .blur-up.lazyloaded {
        filter: blur(0);
      }

Після оголошення стилів, додаємо клас blur-up тегам img. index.html

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