Почему пузыри событий не работают при использовании сетки css с элементами, занимающими одну и ту же ячейку? - PullRequest
1 голос
/ 21 января 2020

У меня есть два дочерних элемента сетки, которые занимают одну и ту же ячейку. У них обоих есть click слушатели событий. В соответствии с всплывающей подсказкой , когда я щелкаю по ячейке, должны запускаться оба прослушивателя событий.

const outer = document.getElementById('outer')
outer.addEventListener('click', () => console.log('on outer click'))

const inner1 = document.getElementById('inner1')
inner1.addEventListener('click', () => console.log('on inner1 click'))

const inner2 = document.getElementById('inner2')
inner2.addEventListener('click', () => console.log('on inner2 click'))
#outer {
  width: 100vw;
  height: 100vh;
  display: grid;
}

#inner2 {
  grid-column: 1/2;
  grid-row: 1/2;
}

#inner1 {
  grid-column: 1/2;
  grid-row: 1/2;
}
<div id="outer">
  <div id="inner1">

  </div>
  <div id="inner2">

  </div>
</div>

Детская площадка: https://jsfiddle.net/o10sfpwu/

Ожидаемый журнал:

on inner2 click
on inner1 click
on outer click

Фактический журнал:

on inner2 click
on outer click

Почему прослушиватель события inner1 не запущен? Событие click должно проходить через все элементы, занимающие это пространство, верно?

Ответы [ 2 ]

2 голосов
/ 21 января 2020

Событие click должно проходить через все элементы, занимающие это пространство, верно?

Событие click (или любое другое событие) будет проходить только через предков DOM элемента. Положение элемента не учитывается, равно как и положение, перекрывающееся с другим элементом во время всплытия события.

В этом случае, поскольку inner2 находится в той же ячейке, что и inner1, и inner2 ставится после inner1 в DOM, inner2 будет на вершине inner1. Таким образом, нажатие на эту ячейку приводит к отправке события на inner2. Затем, чтобы увидеть, какие другие элементы видят событие во время пузырения, посмотрите на предков inner2:

<div id="outer">
  <div id="inner1">

  </div>
  <div id="inner2">

  </div>
</div>

Но его предками являются только #outerdocument.body, и document.documentElement). inner1 не является предком, и событие было отправлено в inner2, поэтому событие не всплывает через inner1.

Это описано в вашей ссылке MDN :

В фазе пузырьков:

  • Браузер проверяет, есть ли на элементе, на который фактически был нажат, обработчик события onclick, зарегистрированный в фазе пузырьков. и запускает его, если так.

  • Затем он переходит к следующему элементу непосредственного предка и делает то же самое, затем к следующему и так далее до оно достигает элемента.

1 голос
/ 21 января 2020

Другой ответ уже правильно отвечает на ваш вопрос, я просто злоупотреблю формой ответа, чтобы указать вам (и, возможно, будущим читателям) на document.elementsFromPoint , который, на мой взгляд, на самом деле соответствует вашим ожиданиям:

const outer = document.getElementById('outer')
outer.addEventListener('click', (evt) => {
  const nodes = document.elementsFromPoint(evt.clientX, evt.clientY);
  nodes.forEach( (node) => console.log( 'clicked over', node));
});
#outer {
  width: 100vw;
  height: 100vh;
  display: grid;
}

#inner2 {
  grid-column: 1/2;
  grid-row: 1/2;
}

#inner1 {
  grid-column: 1/2;
  grid-row: 1/2;
}
<div id="outer">
  <div id="inner1">

  </div>
  <div id="inner2">

  </div>
</div>
...