为什么在使用css网格且元素占据相同单元格时事件冒泡不起作用?

问题描述 投票:1回答:2

我有两个占据相同单元格的网格子级。它们都具有click事件侦听器。根据event bubbling,当我单击单元格时,应同时触发两个事件侦听器。

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事件应该冒泡占据该空间的所有元素,对吧?

javascript html css events css-grid
2个回答
2
投票

click事件应该冒泡占据该空间的所有元素,对吗?

click事件(或任何事件)将仅在元素的DOM祖先中冒泡。事件冒泡时,不考虑元素的位置,也不考虑位置是否与另一个元素重叠。

在这种情况下,由于inner2inner1位于同一单元格,并且inner2放在DOM中的inner1之后,因此inner2将位于inner1的顶部。因此,单击该单元格将导致一个事件被调度到inner2。然后,要查看冒泡时还有哪些其他元素看到了该事件,请查看inner2的祖先:

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

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

  </div>
</div>

但是它的祖先只有#outer(以及document.bodydocument.documentElement)。 inner1不是祖先,并且该事件已调度到inner2,因此该事件不会通过inner1冒泡。

your MDN link中对此进行了描述:

冒泡阶段:

  • 浏览器会检查在冒泡阶段实际单击的元素是否在其上注册了onclick事件处理程序,如果是,则运行该事件处理程序。

  • 然后它前进到下一个直接祖先元素并执行相同的操作,然后执行下一个操作,依此类推,直到到达该元素。


0
投票

[其他答案已经正确回答了您的问题,我只是滥用答案表格将您(以及将来的读者)指向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>
© www.soinside.com 2019 - 2024. All rights reserved.