How to achieve the effect of muscle tissue with absolutely positioned non-descendants?

One of the problems with the standard mouseout event is that it fires not only when the cursor leaves the screen area bounded by the outer perimeter of the element, but also when the cursor hovers over some other element contained in this perimeter.

The rationale for the jQuery mouseleave is to signal only when the cursor leaves the area bounded by the outer perimeter of the element.

Unfortunately, this only works if the “obstruction” element is a descendant of the “blocked” element. If the “obstacle” element is located where it is through absolute positioning, then when the mouse cursor hovers over it, the mouseleave event on the “locked” element is triggered.

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 true descendant of #b-div , while #c-div not, but we can style it so that it “obstructs” #b-div anyway. This is shown in this jsFiddle.

If the following events are now defined on #b-div :

 $( '#b-div' ).bind( { mouseenter: function () { $( this ).addClass( 'outlined' ); }, mouseleave: function () { $( this ).removeClass( 'outlined' ); } } ); 

... then hovering the mouse inside the outer perimeter of #b-div leads to the appearance of a blue outline around this perimeter if the mouse does not end with #c-div .

Is there a way to get the same effect with #b-div and #c-div when mouseleave reaches with #b-div and #d-div ?

EDIT: I installed the example shown in jsFiddle. The original version of this example showed a non-representative particular case where the entire obstructing element overlaps with the locked element. In this special case, the desired effect can be modeled by defining the same events on both obstructing and locked elements, thereby actually turning the obstructing element into a patch of the locked element. This will not work if the obstruction element is not completely contained in the outer perimeter of the closed element (as shown in the modified jsFiddle). More generally, any solution based on using the mouseover event on an obstructive element necessarily fails, since the real problem is to prevent (or make ineffective) a false mouseleave on a blocked element.

+6
source share
2 answers

This is done based on your initial post, in which #c-div fully contained in #b-div :

 $('#b-div, #c-div').on( { mouseenter: function (ev) { $('#b-div').addClass('outlined'); }, mouseleave: function (ev) { $('#b-div').removeClass('outlined'); } }); 

Fiddle 1


Since #c-div may not always be completely contained 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 with the mouse.

Fiddle 2


If you need to interact with #c-div , and it is not completely inside the #b-div , you can use Element.getBoundingClientRect :

 $('#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

+7
source

If you cannot use the pointer-events: none Rich clauses (perhaps you need to support IE 10 or you need to interact with an absolutely positioned div), you can manually verify that the event will not be #c-div using relatedTarget .

However, you also need to check that the mouseleave from #c-div will not be #b-div .

 $( '#b-div' ).bind( { mouseenter: function () { $( this ).addClass( 'outlined' ); }, mouseleave: function (e) { if (e.relatedTarget.id == 'c-div' || $.contains(document.getElementById('c-div'), e.relatedTarget)) { return; } $( this ).removeClass( 'outlined' ); } } ); $( '#c-div' ).bind( { mouseleave: function (e) { if (e.relatedTarget.id == 'b-div' || $.contains(document.getElementById('b-div'), e.relatedTarget)) { return; } $( '#b-div' ).removeClass( 'outlined' ); } }); 
 #a-div { position: relative; margin: 20px; } #b-div { height: 100px; width: 100px; background-color: #555; padding: 50px; } #c-div { position: absolute; height: 50px; width: 200px; top: 100px; left: 100px; background-color: #999; } #d-div { height: 50px; width: 50px; background-color: #ddd; text-align: center; } #c-div span { margin: 21.5px; line-height: 50px; } #d-div span { margin: auto; line-height: 50px; } .outlined { outline: 10px solid steelblue; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="a-div"> <div id="b-div"><div id="d-div"><span>d</span></div></div> <div id="c-div"><span>c</span></div> </div> 
0
source

Source: https://habr.com/ru/post/988335/


All Articles