<MyRusakov.ru />

Создание игр на Unreal Engine 5

Создание игр на Unreal Engine 5

Данный курс научит Вас созданию игр на Unreal Engine 5. Курс состоит из 12 модулей, в которых Вы с нуля освоите этот движок и сможете создавать самые разные игры.

В курсе Вы получите всю необходимую теоретическую часть, а также увидите массу практических примеров. Дополнительно, почти к каждому уроку идут упражнения для закрепления материала.

Помимо самого курса Вас ждёт ещё 8 бесплатных ценных Бонусов: «Chaos Destruction», «Разработка 2D-игры», «Динамическая смена дня и ночи», «Создание динамической погоды», «Создание искусственного интеллекта для NPC», «Создание игры под мобильные устройства», «Создание прототипа RPG с открытым миром» и и весь курс «Создание игр на Unreal Engine 4» (актуальный и в 5-й версии), включающий в себя ещё десятки часов видеоуроков.

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

Делегирование событий в JavaScript: понятное руководство с примерами

Делегирование событий в JavaScript: понятное руководство с примерами

Делегирование событий в JavaScript — один из самых полезных паттернов работы с DOM. Вместо того чтобы назначать обработчик каждому элементу, мы ставим один обработчик на общий контейнер и используем всплытие событий. Это экономит память, упрощает код и отлично работает с динамически добавляемыми узлами.

Что такое делегирование событий

События в браузере всплывают от конкретного узла (event.target) вверх по дереву до документа. Делегирование использует это поведение: обработчик вешается на предка и решает, для кого из потомков событие предназначалось, фильтруя по селектору или атрибуту.

Базовый пример: меню действий в списке

<ul id="users">
  <li>Алиса <button data-action="edit">Редактировать</button> <button data-action="delete">Удалить</button></li>
  <li>Боб <button data-action="edit">Редактировать</button> <button data-action="delete">Удалить</button></li>
</ul>
const list = document.getElementById('users');

list.addEventListener('click', (e) => {
  // Ищем ближайшую кнопку в цепочке всплытия
  const btn = e.target.closest('button');
  if (!btn || !list.contains(btn)) return; // клик не по кнопке внутри #users

  const action = btn.dataset.action; // edit | delete
  const item = btn.closest('li');

  if (action === 'edit') {
    console.log('Редактируем:', item.textContent.trim());
  }
  if (action === 'delete') {
    item.remove();
  }
});

// Новые элементы автоматически поддерживаются делегированием
list.insertAdjacentHTML('beforeend', `<li>Клара <button data-action="edit">Редактировать</button> <button data-action="delete">Удалить</button></li>`);

Мы повесили только один обработчик на #users. Любые новые кнопки внутри списка начнут работать без дополнительного кода — именно поэтому делегирование идеально подходит для динамических интерфейсов.

Как это работает: target и currentTarget

list.addEventListener('click', (e) => {
  console.log('target:', e.target); // исходный узел (например, <span> внутри кнопки)
  console.log('currentTarget:', e.currentTarget); // сам <ul id="users">
});

event.target — где произошел клик. event.currentTarget — элемент, на котором висит обработчик. Для безопасной фильтрации лучше использовать closest и matches.

Фильтрация по селектору: безопаснее и читабельнее

list.addEventListener('click', (e) => {
  const actionBtn = e.target.closest('[data-action]');
  if (!actionBtn || !list.contains(actionBtn)) return;

  if (actionBtn.matches('[data-action="edit"]')) {
    // ...
  } else if (actionBtn.matches('[data-action="delete"]')) {
    // ...
  }
});

closest поднимается вверх по DOM, поэтому срабатывает даже если кликнули по вложенному узлу внутри кнопки.

Делегирование не только кликов: фокус, ввод, контекстное меню

Не все события всплывают одинаково: например, focus и blur не всплывают, но есть аналоги — focusin и focusout. Либо можно использовать режим захвата.

const form = document.querySelector('#profile');

// Вариант 1: всплывающие аналоги
form.addEventListener('focusin', (e) => {
  const input = e.target.closest('input, textarea');
  if (input) input.classList.add('focused');
});
form.addEventListener('focusout', (e) => {
  const input = e.target.closest('input, textarea');
  if (input) input.classList.remove('focused');
});

// Вариант 2: режим захвата (capture)
form.addEventListener('focus', (e) => {
  // ...
}, { capture: true });

Аналогично можно делегировать change, contextmenu, keydown, input и другие события, учитывая их особенности.

Производительность: почему делегирование быстрее

  • Меньше обработчиков — меньше памяти и затрат на регистрацию.
  • Не нужно перевешивать обработчики при перерисовке списка.
  • Меньше закрытий и ссылок, которые мог бы удерживать сборщик мусора.

Для списков на сотни и тысячи элементов делегирование почти всегда выигрывает. Исключения — когда каждый элемент требует уникальную тяжелую логику, привязанную к замыканиям — но такое встречается редко.

Частые ошибки и как их избежать

  • Остановка всплытия в дочерних узлах. Если где-то внутри вызывается e.stopPropagation(), делегирование выше не сработает. Используйте stopPropagation только когда понимаете последствия.
  • Неправильная проверка цели. e.target может быть вложенным элементом (например, <svg> или <span>). Всегда применяйте closest и проверяйте принадлежность контейнеру.
  • Смешивание inline-обработчиков и делегирования. Старайтесь придерживаться одного стиля — это упростит отладку.
  • Злоупотребление innerHTML. Полная замена содержимого контейнера уничтожит состояние (например, выделение, фокус). По возможности меняйте только нужные узлы.

Мини-практика: делегированный ToDo-лист

<form id="todo-form">
  <input name="title" placeholder="Новая задача" required>
  <button>Добавить</button>
</form>
<ul id="todo"></ul>
const formEl = document.getElementById('todo-form');
const listEl = document.getElementById('todo');

formEl.addEventListener('submit', (e) => {
  e.preventDefault();
  const title = new FormData(formEl).get('title');
  listEl.insertAdjacentHTML('beforeend',
    `<li>
      <label>
        <input type="checkbox" data-action="toggle">
        <span class="text">${title}</span>
      </label>
      <button data-action="remove">×</button>
    </li>`
  );
  formEl.reset();
});

listEl.addEventListener('click', (e) => {
  const removeBtn = e.target.closest('[data-action="remove"]');
  if (removeBtn) {
    removeBtn.closest('li').remove();
    return;
  }
});

listEl.addEventListener('change', (e) => {
  const checkbox = e.target.closest('[data-action="toggle"]');
  if (!checkbox) return;
  checkbox.closest('li').classList.toggle('done', checkbox.checked);
});

У нас один обработчик на клик и один на изменение — список может расти бесконечно, но код не усложняется.

Что дальше изучить

  • addEventListener: опции once, passive, capture
  • Поведение редких событий: mouseenter vs mouseover
  • Делегирование на уровне документа: модальные окна, контекстные меню, хоткеи

Если хотите закрепить паттерны на практике и собрать мини‑проекты с нуля до продвинутого уровня, рекомендую пройти интенсив: Пройти практический курс «JavaScript с Нуля до Гуру 2.0» — там много упражнений и разборов кода с обратной связью.

Итоги

Делегирование событий в JavaScript — простой способ ускорить приложение, снизить расход памяти и облегчить работу с динамическим DOM. Запомните три правила: вешайте обработчик на общий контейнер, фильтруйте цель через closest, учитывайте особенности всплытия разных событий. Этого достаточно, чтобы уверенно применять прием в реальных проектах.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (https://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: https://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: https://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.