Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MouseEnter event does not fire when entering parent from child element

I have HTML that looks like this:

<div id="parent">
  <div class="child">
    Child 1
  </div>
  <div class="child">
    Child 2
  </div>
  <div class="child">
    Child 3
  </div>
</div>

I attach mouseenter and mouseout events like so:

$("*").on("mouseenter", function() {
    $(this).addClass("mouse_over");
});

$("*").on("mouseout", function() {
    $(this).removeClass("mouse_over");
});

Now, imagine the following mouse sequence of events:

  1. I move the mouse into the parent div. As expected the mouseenter event fires and the mouse_over class is put on the parent.
  2. I move into one of the children. The mouseout event fires for the parent, and the mouseenter event fires for the child. Good.
  3. I move the mouse back into the parent. The mouseenter DOES NOT fire here.

The third step is the issue here. I want the mouse_over class to be put back on the parent when reentering the parent from its child element.

I think I understand why this is happening, as technically my mouse is in the parent the whole time so firing the mouseenter event does not make sense.

Here's a fiddle better illustrating what I'm trying to do:

https://jsfiddle.net/tg1wg1xx/

If you hover into the parent and children elements, you'll notice on your way out the pattern overlay is not placed on the parent.

So how can I ensure that the overlay is always placed on whatever element I am currently hovering over?

like image 400
thatidiotguy Avatar asked Dec 08 '25 00:12

thatidiotguy


2 Answers

As Boris explained in his answer, there's 2 different events. To quote him :

  • mouseenter and mouseleave are triggered when you enter and leave a hierarchy of nodes, but not when you navigate that hierarchy's descendance.
  • mouseover and mouseout are triggered when the mouse respectively enters and leaves a node's "exclusive" space, so you get a "out" when the mouse gets into a child node.

That being said, you need mouseover and mouseout since you need to trigger the mouse out when hovering a child.

$("*").on("mouseover", function(e) {
    $(this).addClass("mouse_over");
});

$("*").on("mouseout", function(e) {
    $(this).removeClass("mouse_over");
});

Next, you need to know that event bubble in the tree. So when you mouseover on a child, the event is also propagated to the parents. That's why the parent is in hover state even when hovering a child.

To solve that, you need to use .stopPropagation() on the event object.

$("*").on("mouseover", function(e) {
    $(this).addClass("mouse_over");
    e.stopPropagation();
});

$("*").on("mouseout", function(e) {
    $(this).removeClass("mouse_over");
    e.stopPropagation();
});

See it in action


Bonus

In the spirit of writing less code, you can also use that :

$("*").on("mouseover mouseout", function(e) {
    $(this).toggleClass("mouse_over");
    e.stopPropagation();
});
like image 83
Karl-André Gagnon Avatar answered Dec 10 '25 13:12

Karl-André Gagnon


mouse events in javascript can be disorienting. Please note that there are two pairs of events that don't mean the same thing :

  • mouseenter and mouseleave are triggered when you enter and leave a hierarchy of nodes, but not when you navigate that hierarchy's descendance.
  • mouseover and mouseout are triggered when the mouse respectively enters and leaves a node's "exclusive" space, so you get a "out" when the mouse gets into a child node.

the behavior you are observing is because you are mixing the two : I updated your fiddle here https://jsfiddle.net/drxrea7e/1/ to use enter and leave.

you can refer to the events' documentation on mozilla's site for detailed info.

Edit after your comment: ah then we need another thing :

the event actually bubbles, so the parent also receives it (but with target = theChild). So you want to add the class only if event.target == this :see my new version of the fiddle : https://jsfiddle.net/drxrea7e/3/.

The children get the image from the class .mouse_over AND the red color from .parent, because background:url() overwrites background-color:white. Is that what you expected?

like image 45
Boris Avatar answered Dec 10 '25 13:12

Boris



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!