[英]JavaScript - Attaching event handlers to an element also attaches them to its children
I have this HTML. 我有这个HTML。 I want to attach mouseover and mouseleave events ONLY to the
.parent
element, but for some reason they also get attached to the children elements and I get weird behaviour. 我只想将mouseover和mouseleave事件附加到
.parent
元素,但是由于某些原因,它们也附加到children元素,所以我的行为很奇怪。
<div class="parent">
<div class="child-1"></div>
<div class="child-2"></div>
</div>
Here's how I do it 这是我的方法
const parent = document.getElementsByClassName('parent')[0]
parent.addEventListener('mouseover', eventHandler)
parent.addEventListener('mouseleave', eventHandler)
Whats going on and how to prevent it? 发生了什么事以及如何预防?
You have to add event to child nodes and cancel the propagation of the event. 您必须将事件添加到子节点并取消事件的传播。
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>
Or you could do what everyone wants pointer-event
或者您可以做每个人都想要的
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>
It has to do how event catching and bubbling works. 它必须完成事件捕获和冒泡的工作方式。 I copied the @ACD answer to see that it does behave differently.
我复制了@ACD答案,以查看它的行为是否有所不同。 If you notice if we hover on child and move out to the parent the event is not called in this example.
如果您注意到我们是否将鼠标悬停在孩子上并移到父对象上,则在此示例中未调用该事件。 So child elements are no more the target of the event.
因此,子元素不再是事件的目标。
There are two phases of the event, Catching and Bubbling. 该活动分为两个阶段:捕捉和冒泡。 You can find more information here .
您可以在此处找到更多信息。 What is happening that event is triggered for the child and it is bubbling to the parent.
该事件是为孩子触发的,它正在冒泡给父事件。 You can check the event target via
event.target
您可以通过
event.target
检查事件目标
If we remove pointer-events: none;
如果我们删除
pointer-events: none;
then the target is the child not the parent . 那么目标是孩子而不是父母。 and after the child handler is called the vent is propagated to the parent and then the parents callback is called.
并在调用子处理程序之后,将通风口传播到父级,然后调用父级回调。
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>
Try mouseenter
and mouseleave
instead of mouseover
and mouseleave
. 尝试使用
mouseenter
和mouseleave
而不是mouseover
和mouseleave
。 Don't mix them up. 不要把它们混在一起。 It's either the combination of
mouseover/mouseout
or mouseenter/mouseleave
, because these combos are symmetrical. 这是
mouseover/mouseout
或mouseenter/mouseleave
组合,因为这些组合是对称的。
https://developer.mozilla.org/en-US/docs/Web/Events/mouseenter 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>
You could fix this with css, by applying 您可以通过应用CSS来解决此问题
.child-1, .child-2 {
pointer-events: none
}
to the children, that way no interaction with the children is possible. 对孩子来说,这样就不可能与孩子互动。
Alternatively, in the eventhandler you could check if the event.target
is the parent or a childnode, hovering over a childnode will yield the childnode, hovering over .parent
will yield the parent. 另外,在事件处理程序中,您可以检查
event.target
是父节点还是子节点,将鼠标悬停在子.parent
上将产生子节点,将鼠标悬停在.parent
上将产生父节点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.