仅在父单击而不是子单击时触发事件

Posted

技术标签:

【中文标题】仅在父单击而不是子单击时触发事件【英文标题】:trigger event only on parent click not child 【发布时间】:2019-09-25 15:27:47 【问题描述】:

以下面的代码为例:

<div id="parent">
  <div id="child">info goes here</div>
</div>

//javascript
function something
//do something;
//initial attempt
document.getElementById('parent').addEventListener('click',something);
//event capture
document.getElementById('parent').addEventListener('click',something,true);

当我单击父元素时,我希望它做某事,而当我单击子元素时,我希望它什么也不做。问题是,当我单击子元素时,它会触发“某事”。 我认为这可能是事件冒泡,这样如果我点击子元素,事件就会从那里冒泡到父元素。所以后来我在考虑事件捕获,但这也导致了这个问题。

任何关于如何完成此任务的建议或建议将不胜感激。

【问题讨论】:

How do I prevent a parent's onclick event from firing when a child anchor is clicked?的可能重复 【参考方案1】:

相反,检查发起事件Event.target 的元素是否确实是所需的元素。 PS:不要与Event.currentTarget 混淆,后者(相反)始终是附加了事件处理程序的元素。

function something (evt)
  if (evt.target !== this) return; // Do nothing
  // else...
  console.log(`#$this.id clicked`);


const el_parent = document.getElementById('parent');
el_parent.addEventListener('click', something);

// Example why you should not use `Event.stopPropagation()`...
document.body.addEventListener('click', () => console.log("BODY is notified!"));
<div id="parent">
  PARENT ELEMENT
  <div id="child">CHILD ELEMENT</div>
</div>

不要使用Event.stopPropagation()

Event.stopPropagation() 会是一个想法,但是一个糟糕的想法,因为我们应该避免应用程序(在某一层)阻止事件冒泡 - 并最终通知其他元素这样的事件发生了。想象一下您的 body 监听点击事件以关闭自定义选择下拉菜单...如果您的应用程序中有元素在您的应用程序中徘徊,并且使用 Event.stopPropagation() - 单击此类元素,打开的下拉菜单将不会关闭 - 导致 损坏用户界面。这只是一个简单的例子。

【讨论】:

标准答案的好选择,并说明了为什么使用stopPropagation 可能是一个坏主意(即:其他元素,如body 可能需要了解点击)。对于父母可能希望忽略对几个孩子的点击的情况,这也是一种很好的方法,而不必分别为每个孩子添加stopPropagation 没错。感谢您的支持@ericgio【参考方案2】:

使用event.stopPropagation 停止事件冒泡:

function something() 
  console.log("something");

document.getElementById('parent').addEventListener('click', something);
document.getElementById('child').addEventListener('click', e => e.stopPropagation());
<div id="parent">
  Parent info goes here!
  <div id="child">Child info goes here!</div>
</div>

【讨论】:

谢谢你的回答,它解决了我的问题。因此,如果我理解正确,即使我点击了孩子,它仍然是冒泡然后触发父母监听器的“点击”事件? 是的,这是正确的 - 这就是 stopPropagation 停止发生的事情。 @PaulCarlson 你最好不要使用Event.stopPropagation() 并且特别不要为你想要防止事件冒泡的每个元素分配一个事件监听器。这是不正确的。【参考方案3】:

这是事件冒泡。仅仅因为您正在处理child 上的点击事件,并不意味着它停止向父级冒泡。

对此有两种方法。第一个是阻止事件像这样传播: document.getElementById('child').addEventListener('click',(e) =&gt; e.stopPropagation(); something() ,true);

第二种是检查事件目标,只在引起点击事件的最深元素是子元素时才运行something

document.getElementById('child').addEventListener('click',(e) =&gt; e.target.id == "child" ? something() : nothing() ,true);

【讨论】:

以上是关于仅在父单击而不是子单击时触发事件的主要内容,如果未能解决你的问题,请参考以下文章

单击点透

如何在父 li 中捕获子复选框单击事件?

为啥 jQuery 的 .change() 事件只在鼠标右键单击时触发?

单击子锚点时,如何防止触发父级的 onclick 事件?

如何确定“恢复”事件是不是是通过单击图标而不是在 appcelerator 钛中唤醒平板电脑触发的?

jQuery基础篇