I have this 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.
<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
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. 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
If we remove 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
. Don't mix them up. It's either the combination of mouseover/mouseout
or mouseenter/mouseleave
, because these combos are symmetrical.
https://developer.mozilla.org/en-US/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
.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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.