Перейти к содержимому

Всплытие и перехват событий в JavaScript

Осваиваем всплытие и перехват событий в JavaScript

Всплытие и перехват — это две фазы модели распространения событий, которые происходят при срабатывании событий в объектной модели документа (DOM). Понимание этих концепций имеет решающее значение для эффективной обработки событий в сложных веб-приложениях. В этом руководстве объясняются эти концепции и приводятся практические примеры, демонстрирующие, как они работают.


Понимание всплытия и перехвата событий

Распространение событий

Распространение событий в DOM происходит в три фазы:

  1. Фаза перехвата: Событие начинается с вершины дерева DOM (объекта document) и распространяется вниз к целевому элементу.
  2. Целевая фаза: Событие достигает целевого элемента.
  3. Фаза всплытия: После достижения цели событие всплывает от целевого элемента обратно к document.

По умолчанию большинство событий в JavaScript распространяются в фазе всплытия, если не указано иное.

Всплытие событий

На фазе всплытия событие начинается с наиболее конкретного элемента (самой глубокой точки в структуре документа), а затем движется вверх к наименее конкретному узлу (объекту document). Это поведение по умолчанию для большинства событий.

Пример всплытия событий:


html
<div onclick="alert('You clicked the DIV!');">
  Click me or one of my children:
  <p onclick="alert('You clicked the P!');">Click me!</p>
</div>

Если вы нажмете на элемент <p>, сначала появится уведомление для элемента <p>, а затем для элемента <div>, поскольку событие всплывает вверх.

Перехват событий

Перехват — это первая фаза модели распространения событий, на которой событие движется вниз к целевому элементу. Он используется нечасто, но может быть полезен для обработки событий до того, как они достигнут цели.

Чтобы слушать события на фазе перехвата, установите третий аргумент addEventListener в true:


javascript
<div id="outer" onclick="alert('Clicked the DIV!');">
  Click me or one of my children:
  <p id="inner" onclick="alert('Clicked the P!');">Click me!</p>
</div>

<script>
  document.getElementById('outer').addEventListener('click', function() {
    alert('Captured the click on DIV!');
  }, true); // Set to true to handle in the capturing phase

  document.getElementById('inner').addEventListener('click', function() {
    alert('Captured the click on P!');
  }, true);
</script>

Если вы нажмете на элемент <p>, сначала появятся уведомления о перехвате для <div> и <p>, а затем обычные уведомления о всплытии.

Практические примеры всплытия и перехвата событий

Пример 1: Предотвращение всплытия событий

Иногда вам может потребоваться остановить всплытие события по дереву DOM:


html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Event Propagation Example</title>
<style>
  .container {
    width: 200px;
    height: 200px;
    background-color: lightblue;
    padding: 20px;
  }

  .box {
    width: 100px;
    height: 100px;
    background-color: pink;
    margin-top: 20px;
    cursor: pointer;
  }
</style>
</head>
<body>

<div class="container" onclick="alert('You clicked the container!');">
  Click the pink box to see event propagation:
  <div class="box" onclick="event.stopPropagation(); alert('You clicked the box without bubbling!');"></div>
</div>

</body>
</html>

В этом примере есть контейнер со светло-голубым фоном, содержащий розовый блок. Нажатие в любом месте внутри контейнера вызывает уведомление «Вы нажали на контейнер!». Однако нажатие на розовый блок вызывает другое уведомление «Вы нажали на блок без всплытия!», поскольку event.stopPropagation() предотвращает всплытие события клика к контейнеру.

Пример 2: Использование всплытия и перехвата

Этот пример показывает, как обработать событие на фазах перехвата и всплытия:


html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Event Capture and Bubbling Example</title>
<style>
  body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
  }

  #outerContainer {
    border: 2px solid #ccc;
    padding: 20px;
    margin-bottom: 20px;
    background-color: #f9f9f9;
    border-radius: 10px;
  }

  #innerElement {
    background-color: #ffa8a8;
    padding: 10px;
    border-radius: 5px;
    cursor: pointer;
  }
</style>
</head>
<body>

<div id="outerContainer" onclick="alert('Event Bubbled from Outer Container');">
  <p style="margin: 0;">Click anywhere in this outer container:</p>
  <p id="innerElement">Click me!</p>
</div>

<script>
  // Event listener attached to the outer container during the capturing phase
  document.getElementById('outerContainer').addEventListener('click', function() {
    alert('Event Captured by Outer Container');
  }, true);

  // Event listener attached to the inner element during the bubbling phase
  document.getElementById('innerElement').addEventListener('click', function() {
    alert('Event Bubbled from Inner Element');
  }, false);
</script>

</body>
</html>
  • Внешний контейнер (#outerContainer): Представьте его как самую большую коробку. Внутри него есть текст: «Нажмите в любом месте этого внешнего контейнера:». Внутри этой коробки находится еще одна, меньшая.

    • Внутренний элемент (#innerElement): Это меньшая коробка внутри большой. В ней есть текст: «Click me!». Этот блок находится внутри внешнего контейнера.
  • Обработчики событий:

    • Перехват события: Когда вы нажимаете в любом месте внешнего контейнера, сначала срабатывает уведомление «Event Captured by Outer Container». Это похоже на то, как кто-то ловит событие при входе во внешний контейнер.
    • Всплытие события: Если вы нажмете на внутреннюю коробку («Click me!»), событие всплывает. Это похоже на пузырь, поднимающийся от внутренней коробки к внешней. Когда он достигает внешнего контейнера, срабатывает еще одно уведомление «Event Bubbled from Inner Element».

Таким образом, внешний контейнер перехватывает событие при нажатии в любом месте, а если вы нажмете на внутреннюю коробку, событие всплывает к внешнему контейнеру. Так работают перехват и всплытие событий в HTML!

Заключение

Понимание всплытия и перехвата событий позволяет эффективно управлять распространением событий в ваших веб-приложениях. Управляя обработкой событий на этих фазах, вы можете повысить интерактивность приложения, предотвратить нежелательное распространение событий и обеспечить обработку событий в соответствии с вашими конкретными потребностями.

Практика

Какие две фазы распространения событий упоминаются в указанной ссылке?

Считаете ли это полезным?

Предпросмотр dual-run — сравните с маршрутами Symfony на продакшене.