← Назад к вопросам

Будет ли работать Bubbling при наличии события onClick на родительском и дочернем элементах?

2.0 Middle🔥 151 комментариев
#JavaScript Core

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

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

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

Будет ли работать Bubbling при наличии события onClick на родительском и дочернем элементах

Да, bubbling будет работать полностью. События будут срабатывать сначала на дочернем элементе, а потом будут "всплывать" вверх к родительским элементам.

Как это работает

Event bubbling (всплытие событий) - это процесс, при котором событие, возникшее на элементе, распространяется вверх по DOM дереву.

<div class="parent" onclick="handleParentClick()">
  Родитель
  <button class="child" onclick="handleChildClick()">
    Дочерний элемент
  </button>
</div>

Когда вы кликните на кнопку, произойдёт:

1. handleChildClick() -> выполнится (на дочернем элементе)
2. handleParentClick() -> выполнится (на родителе)
3. Событие всплывает дальше по цепи

Пример с консолью

function handleParent() {
  console.log("Родитель clicked");
}

function handleChild() {
  console.log("Дочерний clicked");
}
<div onclick="handleParent()">
  <button onclick="handleChild()">
    Кликни
  </button>
</div>

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

Дочерний clicked
Родитель clicked

Фазы события

Событие проходит 3 фазы:

1. CAPTURING (захват) - события идут вниз
   window -> document -> html -> body -> parent -> child

2. TARGET (цель) - событие на самом элементе
   child

3. BUBBLING (всплытие) - события идут вверх
   child -> parent -> body -> html -> document -> window

По умолчанию onclick слушает фазу BUBBLING (всплытие).

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

function Parent() {
  const handleParentClick = (e) => {
    console.log("Parent clicked");
  };

  return (
    <div onClick={handleParentClick}>
      <Child />
    </div>
  );
}

function Child() {
  const handleChildClick = (e) => {
    console.log("Child clicked");
  };

  return <button onClick={handleChildClick}>Click me</button>;
}

В консоли:

Child clicked
Parent clicked

Остановка Bubbling: stopPropagation()

Чтобы предотвратить всплытие события, используй stopPropagation():

function handleChild(e) {
  e.stopPropagation(); // Остановить всплытие
  console.log("Child clicked");
  // Parent click handler НЕ будет вызван
}

function handleParent() {
  console.log("Parent clicked");
}

Результат:

Child clicked
(Parent clicked НЕ будет в консоли)

Полностью остановить обработку: stopImmediatePropagation()

const child = document.querySelector('.child');

// Первый обработчик
child.addEventListener('click', (e) => {
  e.stopImmediatePropagation();
  console.log("First handler");
});

// Второй обработчик на том же элементе
child.addEventListener('click', (e) => {
  console.log("Second handler"); // НЕ выполнится
});

Event Delegation (делегирование событий)

Когда много элементов с одинаковым обработчиком, можно использовать bubbling:

<ul id="list">
  <li>Элемент 1</li>
  <li>Элемент 2</li>
  <li>Элемент 3</li>
</ul>
// НЕПРАВИЛЬНО: обработчик на каждый элемент
const items = document.querySelectorAll('li');
items.forEach(item => {
  item.addEventListener('click', (e) => {
    console.log('Clicked:', e.target.textContent);
  });
});

// ПРАВИЛЬНО: обработчик на родителя
const list = document.getElementById('list');
list.addEventListener('click', (e) => {
  if (e.target.tagName === 'LI') {
    console.log('Clicked:', e.target.textContent);
  }
});

React: onClick vs addEventListener

React нормализует события - onClick всегда работает с bubbling-фазой, даже если нативно событие не всплывает.

function App() {
  return (
    <div onClick={() => console.log("Parent")}>
      {/* Все эти события будут всплывать до parent div */}
      <input onChange={() => console.log("Input")} />
      <video onPlay={() => console.log("Video")} />
      <img onLoad={() => console.log("Image")} />
    </div>
  );
}

Отключение Bubbling в React

В React нет прямого аналога addEventListener с опцией capture, но можно использовать:

function Child() {
  const handleClick = (e) => {
    e.stopPropagation(); // Остановить всплытие
    console.log("Child");
  };

  return <button onClick={handleClick}>Child</button>;
}

function Parent() {
  return (
    <div onClick={() => console.log("Parent")}>
      <Child />
    </div>
  );
}

Результат:

Child
(Parent НЕ будет)

Capturing фаза (редко используется)

// Слушать на фазе CAPTURING (не BUBBLING)
document.addEventListener('click', (e) => {
  console.log("Capturing:", e.eventPhase); // 1 = CAPTURING
}, true); // true = capturing фаза

// Слушать на фазе BUBBLING (по умолчанию)
document.addEventListener('click', (e) => {
  console.log("Bubbling:", e.eventPhase); // 3 = BUBBLING
}, false); // false = bubbling фаза

Порядок выполнения:

1. Capturing phase: "Capturing: 1"
2. Target phase: (на самом элементе)
3. Bubbling phase: "Bubbling: 3"

Практическая ошибка: случайное закрытие dropdown

function Dropdown() {
  const [isOpen, setIsOpen] = useState(false);

  // НЕПРАВИЛЬНО: dropdown закроется при клике на кнопку
  return (
    <div onClick={() => setIsOpen(false)}>
      <button onClick={() => setIsOpen(!isOpen)}>
        Меню
      </button>
      {isOpen && <ul>Опции</ul>}
    </div>
  );
}

// ПРАВИЛЬНО: остановить всплытие
function Dropdown() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div onClick={() => setIsOpen(false)}>
      <button 
        onClick={(e) => {
          e.stopPropagation(); // Не закрывать на клик кнопки
          setIsOpen(!isOpen);
        }}
      >
        Меню
      </button>
      {isOpen && <ul>Опции</ul>}
    </div>
  );
}

Важные события, которые НЕ всплывают

Не все события всплывают:

// НЕ всплывают (по умолчанию):
focus, blur, load, unload, scroll, reset, submit, resize, etc.

// Всплывают:
click, dblclick, mousedown, mouseup, mouseover, mouseout, keydown, keyup, etc.

Проверить можно через свойство bubbles:

const clickEvent = new Event('click');
console.log(clickEvent.bubbles); // true

const focusEvent = new Event('focus');
console.log(focusEvent.bubbles); // false

Итог

  • Bubbling работает с onClick на родителе и дочернем элементе
  • Очерёдность: сначала дочерний, потом родитель
  • stopPropagation() останавливает всплытие
  • Event delegation использует bubbling для эффективной обработки многих элементов
  • React нормализует события, поэтому onClick работает предсказуемо
  • Не все события всплывают (focus, blur, load, etc.)
Будет ли работать Bubbling при наличии события onClick на родительском и дочернем элементах? | PrepBro