One problem with the standard mouseout
event is that it fires not only when the cursor leaves the region of the screen bounded by the element's external perimeter, but also when the cursor hovers over some other element contained within this perimeter.
The rationale for jQuery's mouseleave
event is to signal only the moment when the cursor leaves the the area bounded by an element's external perimeter.
Unfortunately, this seems to work only if the "obstructing" element is a descendant of the "obstructed" element. If the "obstructing" element is where it is through absolute positioning, then when the mouse hovers over it, the mouseleave
event on the "obstructed" element gets fired.
For example, with the following HTML:
<div id="b-div">
<div id="d-div"><span>d</span></div>
</div>
<div id="c-div"><span>c</span></div>
...#d-div
is a bona-fide descendant of #b-div
, whereas #c-div
isn't, but, but we can style it so that it "obstructs" #b-div
all the same. This is illustrated in this jsFiddle.
If now one defines the following events on #b-div
:
$( '#b-div' ).bind( {
mouseenter: function () {
$( this ).addClass( 'outlined' );
},
mouseleave: function () {
$( this ).removeClass( 'outlined' );
}
} );
...then hovering the mouse within #b-div
's outer perimeter causes a blue outline to appear over this perimeter, unless the mouse is over #c-div
.
Is there a way to get the same effect with #b-div
and #c-div
as mouseleave
achieves with #b-div
and #d-div
?
EDIT: I've fixed the example shown in the jsFiddle. The original version of this example showed the unrepresentative special case in which all of the obstructing element overlaps with the obstructed element. In this special case, the desired effect can be simulated by defining the same events on both the obstructing and the obstructed elements, thus, in effect, turning the obstructing element into a patch of the obstructed element. This won't work when the obstructing element is not fully contained within the obstructed element's outer perimeter (as shown in the amended jsFiddle). More generally, any solution that is based on using a mouseover
event on the obstructing element is bound to fail, since the real problem is to prevent (or render ineffective) the spurious mouseleave
on the obstructed element.
The mouse leave event will be triggered whenever the mouse cursor leaves from the selected element and after the occurrence of the event, it implements a mouse leave event that has been attached to an event handler function to run.
This means that mouseleave is fired when the pointer has exited the element and all of its descendants, whereas mouseout is fired when the pointer leaves the element or leaves one of the element's descendants (even if the pointer is still within the element).
The mouseleave event occurs when the mouse pointer leaves the selected element. The mouseleave() method triggers the mouseleave event, or attaches a function to run when a mouseleave event occurs. Note: Unlike the mouseout event, the mouseleave event only triggers when the mouse pointer leaves the selected elements.
The mouseover event triggers when the mouse pointer enters the div element, and its child elements. The mouseenter event is only triggered when the mouse pointer enters the div element. The onmousemove event triggers every time the mouse pointer is moved over the div element.
This does it, based on your initial post in which #c-div
was completely contained within #b-div
:
$('#b-div, #c-div').on( {
mouseenter: function (ev) {
$('#b-div').addClass('outlined');
},
mouseleave: function (ev) {
$('#b-div').removeClass('outlined');
}
});
Fiddle 1
#c-div
may not always be contained completely within #b-div
, you can use your existing code if you add this style:
#c-div {
pointer-events: none;
}
But this will make it impossible to interact with #c-div
using the mouse.
Fiddle 2
If you do need to interact with #c-div
, and it's not completely within #b-div
, you can use Element.getBoundingClientRect like this:
$('#b-div, #c-div').on('mousemove mouseleave',
function(ev) {
var br= $('#b-div')[0].getBoundingClientRect();
$('#b-div').toggleClass(
'outlined',
ev.pageX > br.left && ev.pageX < br.left+br.width &&
ev.pageY > br.top && ev.pageY < br.top +br.height
)
}
);
Fiddle 3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With