\n```\n\n**2. Слушатель события (Event Listener)**\n\nФункция, которая вызывается при событии:\n\n```javascript\nfunction handleClick(event) {\n console.log('Кнопка нажата!');\n}\n\n// Способ 1: addEventListener (рекомендуется)\nbutton.addEventListener('click', handleClick);\n\n// Способ 2: атрибут в HTML (старый стиль)\n// \n\n// Способ 3: свойство (устаревает)\nbutton.onclick = handleClick;\n```\n\n**3. Объект события (Event Object)**\n\nСодержит информацию о событии:\n\n```javascript\nbutton.addEventListener('click', (event) => {\n console.log(event.type); // 'click'\n console.log(event.target); // элемент, на котором событие\n console.log(event.currentTarget); // элемент, слушатель которого вызовется\n console.log(event.timeStamp); // время события\n console.log(event.defaultPrevented); // предотвращено ли стандартное поведение\n});\n```\n\n### Фазы события (Event Phases)\n\n**Трёхфазная модель событий:**\n\n```html\n
\n
\n \n
\n
\n\n\n```\n\n**Использование всплытия:**\n- Оптимизация памяти (один слушатель вместо сотен)\n- Динамические элементы (новые элементы автоматически слушаются)\n- Делегирование ответственности\n\n### Event Capturing (Захват)\n\n**Событие распространяется от корня вниз к целевому элементу:**\n\n```javascript\nbutton.addEventListener('click', (e) => {\n console.log('Bubbling');\n}, false); // false или omitted = bubbling фаза\n\nbutton.addEventListener('click', (e) => {\n console.log('Capturing');\n}, true); // true = capturing фаза\n\n// При клике выведет:\n// Capturing\n// Bubbling\n```\n\n**Capturing используется редко** (в основном для специальных целей).\n\n### Остановка распространения события\n\n```javascript\nbutton.addEventListener('click', (event) => {\n // Остановить ВСПЛЫТИЕ события\n event.stopPropagation();\n \n // Остановить стандартное поведение (не используется с bubbling/capturing)\n event.preventDefault();\n \n // Остановить ВСЁ (и bubbling и другие слушатели)\n event.stopImmediatePropagation();\n});\n```\n\n**Пример с реальным кейсом:**\n\n```javascript\n// Модальное окно\nconst modal = document.getElementById('modal');\nconst backdrop = document.getElementById('backdrop');\n\nbackdrop.addEventListener('click', (e) => {\n // Закрыть модаль при клике на фон\n closeModal();\n});\n\nmodal.addEventListener('click', (e) => {\n // Но НЕ закрыть при клике внутри модали\n e.stopPropagation();\n});\n```\n\n### Частые события\n\n```javascript\n// Мышь\nbutton.addEventListener('click', handler); // клик\nbutton.addEventListener('dblclick', handler); // двойной клик\nbutton.addEventListener('mousedown', handler); // нажата кнопка мыши\nbutton.addEventListener('mouseup', handler); // отпущена кнопка мыши\nbutton.addEventListener('mouseover', handler); // мышь над элементом\nbutton.addEventListener('mouseout', handler); // мышь ушла из элемента\nbutton.addEventListener('mousemove', handler); // движение мыши\n\n// Клавиатура\ninput.addEventListener('keydown', handler); // нажата клавиша\ninput.addEventListener('keyup', handler); // отпущена клавиша\ninput.addEventListener('keypress', handler); // нажата символьная клавиша (устаревает)\n\n// Форма\nform.addEventListener('submit', handler); // отправка формы\ninput.addEventListener('change', handler); // изменилось значение\ninput.addEventListener('input', handler); // вводится текст (в реальном времени)\n\n// Документ\ndocument.addEventListener('DOMContentLoaded', handler); // DOM готов\nwindow.addEventListener('load', handler); // страница полностью загружена\nwindow.addEventListener('scroll', handler); // прокрутка\n```\n\n### В React\n\nReact имеет свою событийную систему (SyntheticEvent):\n\n```javascript\nfunction Button() {\n const handleClick = (event) => {\n console.log(event.type); // 'click'\n console.log(event.target); // DOM элемент\n event.preventDefault(); // стандартное behavior\n event.stopPropagation(); // остановить bubbling\n };\n\n return ;\n}\n```\n\n**Важно:** React 17+ использует собственные события на корневом элементе (event delegation).\n\n### Event Delegation в React\n\n```javascript\nfunction TodoList() {\n const handleTodoClick = (event) => {\n const todoId = event.currentTarget.dataset.id;\n console.log('Клик на todo:', todoId);\n };\n\n return (\n \n );\n}\n```\n\n### Custom Events (Пользовательские события)\n\nМожно создавать свои события:\n\n```javascript\n// Создание события\nconst event = new CustomEvent('myEvent', {\n detail: { message: 'Привет!' }\n});\n\n// Отправка события\nbutton.dispatchEvent(event);\n\n// Слушание события\nbutton.addEventListener('myEvent', (e) => {\n console.log(e.detail.message); // 'Привет!'\n});\n```\n\n**Практический пример:**\n\n```javascript\n// Компонент отправляет событие\nclass DataLoader {\n async loadData() {\n const data = await fetch('/api/data');\n \n // Отправляем событие после загрузки\n const event = new CustomEvent('dataLoaded', {\n detail: { data }\n });\n document.dispatchEvent(event);\n }\n}\n\n// Другой компонент слушает событие\ndocument.addEventListener('dataLoaded', (e) => {\n console.log('Данные загружены:', e.detail.data);\n});\n```\n\n### Лучшие практики\n\n**1. Используйте addEventListener вместо onclick атрибута**\n\n```javascript\n// Плохо\n// \n\n// Хорошо\nbutton.addEventListener('click', handleClick);\n```\n\n**2. Используйте Event Delegation для динамических элементов**\n\n```javascript\n// Плохо - не работает для новых элементов\nconst items = document.querySelectorAll('.item');\nitems.forEach(item => {\n item.addEventListener('click', handleItem);\n});\n\n// Хорошо - работает для новых элементов\ncontainer.addEventListener('click', (e) => {\n const item = e.target.closest('.item');\n if (item) handleItem(e);\n});\n```\n\n**3. Всегда удаляйте слушатели при очистке**\n\n```javascript\nfunction MyComponent() {\n useEffect(() => {\n const handleResize = () => console.log('resize');\n \n window.addEventListener('resize', handleResize);\n \n return () => {\n // Очистка важна!\n window.removeEventListener('resize', handleResize);\n };\n }, []);\n}\n```\n\n**4. Избегайте множественных addEventListener с одной функцией**\n\n```javascript\n// Сложно удалить\nbutton.addEventListener('click', handler);\nbutton.addEventListener('click', handler); // Добавится ещё раз\n\n// Правильно\nfunction setupButton() {\n button.addEventListener('click', handler);\n}\n\nfunction teardownButton() {\n button.removeEventListener('click', handler);\n}\n```\n\n### Итог\n\n**Событийная модель включает:**\n- **Источник события** (целевой элемент)\n- **Слушатель события** (функция-обработчик)\n- **Объект события** (информация о событии)\n- **Фазы события** (capturing, target, bubbling)\n\n**Ключевые моменты:**\n1. События всплывают вверх по DOM\n2. Event Delegation экономит память\n3. Всегда удаляйте слушатели после использования\n4. В React используйте синтетические события\n5. Для специальных нужд создавайте Custom Events","dateCreated":"2026-04-02T21:50:11.441367","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Что такое событийная модель?

2.3 Middle🔥 192 комментариев
#Браузер и сетевые технологии

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое событийная модель

Событийная модель — это механизм взаимодействия между пользователем, браузером и JavaScript кодом. Она определяет, как события (клики, ввод текста, прокрутка) распространяются через DOM и обрабатываются компонентами.

Основные компоненты события

1. Источник события (Event Target)

Элемент, на котором произошло событие:

<button id="btn">Нажми меня</button>

<script>
  const btn = document.getElementById('btn');
  btn.addEventListener('click', (event) => {
    console.log(event.target); // <button id="btn">...</button>
    console.log(event.target === btn); // true
  });
</script>

2. Слушатель события (Event Listener)

Функция, которая вызывается при событии:

function handleClick(event) {
  console.log('Кнопка нажата!');
}

// Способ 1: addEventListener (рекомендуется)
button.addEventListener('click', handleClick);

// Способ 2: атрибут в HTML (старый стиль)
// <button onclick="handleClick(event)">...</button>

// Способ 3: свойство (устаревает)
button.onclick = handleClick;

3. Объект события (Event Object)

Содержит информацию о событии:

button.addEventListener('click', (event) => {
  console.log(event.type);        // 'click'
  console.log(event.target);      // элемент, на котором событие
  console.log(event.currentTarget); // элемент, слушатель которого вызовется
  console.log(event.timeStamp);   // время события
  console.log(event.defaultPrevented); // предотвращено ли стандартное поведение
});

Фазы события (Event Phases)

Трёхфазная модель событий:

<div id="outer">
  <div id="middle">
    <button id="inner">Нажми</button>
  </div>
</div>

<script>
const outer = document.getElementById('outer');
const middle = document.getElementById('middle');
const inner = document.getElementById('inner');

// Фаза 1: Capturing (захват) - событие идет ВНИЗ по дереву
outer.addEventListener('click', (e) => {
  console.log('Outer - CAPTURING');
}, true); // true = использовать capturing фазу

middle.addEventListener('click', (e) => {
  console.log('Middle - CAPTURING');
}, true);

inner.addEventListener('click', (e) => {
  console.log('Inner - CAPTURING');
}, true);

// Фаза 2: Target - событие достигло целевого элемента
outer.addEventListener('click', (e) => {
  console.log('Outer - TARGET');
});

middle.addEventListener('click', (e) => {
  console.log('Middle - TARGET');
});

inner.addEventListener('click', (e) => {
  console.log('Inner - TARGET');
});

// Фаза 3: Bubbling (всплытие) - событие идет ВВЕРХ по дереву
outer.addEventListener('click', (e) => {
  console.log('Outer - BUBBLING');
});

middle.addEventListener('click', (e) => {
  console.log('Middle - BUBBLING');
});

inner.addEventListener('click', (e) => {
  console.log('Inner - BUBBLING');
});

// При клике на кнопку выведет:
// Outer - CAPTURING
// Middle - CAPTURING
// Inner - CAPTURING
// Inner - TARGET
// Inner - BUBBLING
// Middle - BUBBLING
// Outer - BUBBLING

Event Bubbling (Всплытие)

Событие распространяется от элемента вверх к родительским элементам:

<div class="container">
  <ul id="list">
    <li><a href="#">Пункт 1</a></li>
    <li><a href="#">Пункт 2</a></li>
    <li><a href="#">Пункт 3</a></li>
  </ul>
</div>

<script>
// Было бы неудобно:получать слушатель на каждый <a>
// const links = document.querySelectorAll('a');
// links.forEach(link => {
//   link.addEventListener('click', handleLinkClick);
// });

// Лучше использовать Event Delegation (делегирование):
const list = document.getElementById('list');
list.addEventListener('click', (event) => {
  const link = event.target.closest('a');
  if (link) {
    event.preventDefault();
    console.log('Клик на ссылку:', link.textContent);
  }
});
</script>

Использование всплытия:

  • Оптимизация памяти (один слушатель вместо сотен)
  • Динамические элементы (новые элементы автоматически слушаются)
  • Делегирование ответственности

Event Capturing (Захват)

Событие распространяется от корня вниз к целевому элементу:

button.addEventListener('click', (e) => {
  console.log('Bubbling');
}, false); // false или omitted = bubbling фаза

button.addEventListener('click', (e) => {
  console.log('Capturing');
}, true); // true = capturing фаза

// При клике выведет:
// Capturing
// Bubbling

Capturing используется редко (в основном для специальных целей).

Остановка распространения события

button.addEventListener('click', (event) => {
  // Остановить ВСПЛЫТИЕ события
  event.stopPropagation();
  
  // Остановить стандартное поведение (не используется с bubbling/capturing)
  event.preventDefault();
  
  // Остановить ВСЁ (и bubbling и другие слушатели)
  event.stopImmediatePropagation();
});

Пример с реальным кейсом:

// Модальное окно
const modal = document.getElementById('modal');
const backdrop = document.getElementById('backdrop');

backdrop.addEventListener('click', (e) => {
  // Закрыть модаль при клике на фон
  closeModal();
});

modal.addEventListener('click', (e) => {
  // Но НЕ закрыть при клике внутри модали
  e.stopPropagation();
});

Частые события

// Мышь
button.addEventListener('click', handler);      // клик
button.addEventListener('dblclick', handler);   // двойной клик
button.addEventListener('mousedown', handler);  // нажата кнопка мыши
button.addEventListener('mouseup', handler);    // отпущена кнопка мыши
button.addEventListener('mouseover', handler);  // мышь над элементом
button.addEventListener('mouseout', handler);   // мышь ушла из элемента
button.addEventListener('mousemove', handler);  // движение мыши

// Клавиатура
input.addEventListener('keydown', handler);   // нажата клавиша
input.addEventListener('keyup', handler);     // отпущена клавиша
input.addEventListener('keypress', handler);  // нажата символьная клавиша (устаревает)

// Форма
form.addEventListener('submit', handler);     // отправка формы
input.addEventListener('change', handler);   // изменилось значение
input.addEventListener('input', handler);    // вводится текст (в реальном времени)

// Документ
document.addEventListener('DOMContentLoaded', handler); // DOM готов
window.addEventListener('load', handler);              // страница полностью загружена
window.addEventListener('scroll', handler);            // прокрутка

В React

React имеет свою событийную систему (SyntheticEvent):

function Button() {
  const handleClick = (event) => {
    console.log(event.type);        // 'click'
    console.log(event.target);      // DOM элемент
    event.preventDefault();          // стандартное behavior
    event.stopPropagation();         // остановить bubbling
  };

  return <button onClick={handleClick}>Нажми</button>;
}

Важно: React 17+ использует собственные события на корневом элементе (event delegation).

Event Delegation в React

function TodoList() {
  const handleTodoClick = (event) => {
    const todoId = event.currentTarget.dataset.id;
    console.log('Клик на todo:', todoId);
  };

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id} data-id={todo.id} onClick={handleTodoClick}>
          {todo.title}
        </li>
      ))}
    </ul>
  );
}

Custom Events (Пользовательские события)

Можно создавать свои события:

// Создание события
const event = new CustomEvent('myEvent', {
  detail: { message: 'Привет!' }
});

// Отправка события
button.dispatchEvent(event);

// Слушание события
button.addEventListener('myEvent', (e) => {
  console.log(e.detail.message); // 'Привет!'
});

Практический пример:

// Компонент отправляет событие
class DataLoader {
  async loadData() {
    const data = await fetch('/api/data');
    
    // Отправляем событие после загрузки
    const event = new CustomEvent('dataLoaded', {
      detail: { data }
    });
    document.dispatchEvent(event);
  }
}

// Другой компонент слушает событие
document.addEventListener('dataLoaded', (e) => {
  console.log('Данные загружены:', e.detail.data);
});

Лучшие практики

1. Используйте addEventListener вместо onclick атрибута

// Плохо
// <button onclick="handleClick()">Нажми</button>

// Хорошо
button.addEventListener('click', handleClick);

2. Используйте Event Delegation для динамических элементов

// Плохо - не работает для новых элементов
const items = document.querySelectorAll('.item');
items.forEach(item => {
  item.addEventListener('click', handleItem);
});

// Хорошо - работает для новых элементов
container.addEventListener('click', (e) => {
  const item = e.target.closest('.item');
  if (item) handleItem(e);
});

3. Всегда удаляйте слушатели при очистке

function MyComponent() {
  useEffect(() => {
    const handleResize = () => console.log('resize');
    
    window.addEventListener('resize', handleResize);
    
    return () => {
      // Очистка важна!
      window.removeEventListener('resize', handleResize);
    };
  }, []);
}

4. Избегайте множественных addEventListener с одной функцией

// Сложно удалить
button.addEventListener('click', handler);
button.addEventListener('click', handler); // Добавится ещё раз

// Правильно
function setupButton() {
  button.addEventListener('click', handler);
}

function teardownButton() {
  button.removeEventListener('click', handler);
}

Итог

Событийная модель включает:

  • Источник события (целевой элемент)
  • Слушатель события (функция-обработчик)
  • Объект события (информация о событии)
  • Фазы события (capturing, target, bubbling)

Ключевые моменты:

  1. События всплывают вверх по DOM
  2. Event Delegation экономит память
  3. Всегда удаляйте слушатели после использования
  4. В React используйте синтетические события
  5. Для специальных нужд создавайте Custom Events
Что такое событийная модель? | PrepBro