繁体   English   中英

JavaScript-将事件处理程序附加到元素还将其附加到其子元素

[英]JavaScript - Attaching event handlers to an element also attaches them to its children

我有这个HTML。 我只想将mouseover和mouseleave事件附加到.parent元素,但是由于某些原因,它们也附加到children元素,所以我的行为很奇怪。

<div class="parent">
  <div class="child-1"></div>
  <div class="child-2"></div>
</div>

这是我的方法

const parent = document.getElementsByClassName('parent')[0]
parent.addEventListener('mouseover', eventHandler)
parent.addEventListener('mouseleave', eventHandler)

发生了什么事以及如何预防?

您必须将事件添加到子节点并取消事件的传播。

 const parent = document.getElementsByClassName('parent')[0] parent.addEventListener('mouseover', eventHandler) parent.addEventListener('mouseleave', eventHandler) for (const child of parent.childNodes) { child.addEventListener('mouseover', function(event) { event.stopPropagation(); }) child.addEventListener('mouseleave', function(event) { event.stopPropagation(); }) } function eventHandler() { console.log('hey'); } 
 <div class="parent" style="width: 25px; height: 25px; background: red; padding: 50px"> <div class="child-1" style="width: 25px; height: 25px; background: blue"></div> <div class="child-2" style="width: 25px; height: 25px; background: green"></div> </div> 

或者您可以做每个人都想要的pointer-event

 const parent = document.getElementsByClassName('parent')[0] parent.addEventListener('mouseover', eventHandler) parent.addEventListener('mouseleave', eventHandler) for (const child of parent.childNodes) { child.className += ' no-event' } function eventHandler() { console.log('hey'); } 
 .no-event { pointer-events: none; } 
 <div class="parent" style="width: 25px; height: 25px; background: red; padding: 50px"> <div class="child-1" style="width: 25px; height: 25px; background: blue"></div> <div class="child-2" style="width: 25px; height: 25px; background: green"></div> </div> 

它必须完成事件捕获和冒泡的工作方式。 我复制了@ACD答案,以查看它的行为是否有所不同。 如果您注意到我们是否将鼠标悬停在孩子上并移到父对象上,则在此示例中未调用该事件。 因此,子元素不再是事件的目标。

该活动分为两个阶段:捕捉和冒泡。 您可以在此处找到更多信息。 该事件是为孩子触发的,它正在冒泡给父事件。 您可以通过event.target检查事件目标

如果我们删除pointer-events: none; 那么目标是孩子而不是父母。 并在调用子处理程序之后,将通风口传播到父级,然后调用父级回调。

 const parent = document.getElementsByClassName('parent')[0] parent.addEventListener('mouseover', eventHandler) parent.addEventListener('mouseleave', eventHandler) function eventHandler(e) { console.log(e.target, 'hey'); } 
 <div class="parent" style="width: 25px; height: 25px; background: red; padding: 50px"> <div class="child-1" style="pointer-events: none; width: 25px; height: 25px; background: blue"></div> <div class="child-2" style="pointer-events: none; width: 25px; height: 25px; background: green"></div> </div> 

尝试使用mouseentermouseleave而不是mouseovermouseleave 不要把它们混在一起。 这是mouseover/mouseoutmouseenter/mouseleave组合,因为这些组合是对称的。

https://developer.mozilla.org/zh-CN/docs/Web/Events/mouseenter

 var logs = document.querySelector('.log'); var area = document.querySelector('.parent'); function eventHandler (e) { if (e.type === 'mouseenter') { area.style.backgroundColor = '#c00'; } else { area.style.backgroundColor = ''; } } area.addEventListener('mouseenter', eventHandler); area.addEventListener('mouseleave', eventHandler); 
 .parent { background: #eee; } .child { padding: 30px 20px; } .child + .child { border-top: 1px dotted #333; } 
 <div class="parent"> <div class="child"> foo bar baz </div> <div class="child"> foo bar baz </div> </div> 

您可以通过应用CSS来解决此问题

.child-1, .child-2 {
  pointer-events: none
}

对孩子来说,这样就不可能与孩子互动。

另外,在事件处理程序中,您可以检查event.target是父节点还是子节点,将鼠标悬停在子.parent上将产生子节点,将鼠标悬停在.parent上将产生父节点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM