Problem description
I hope that when the mouse moves to id1, id2 will be displayed, and when the mouse leaves id1, id2 will be displayed. The questions are as follows:
1. When the mouse moves from id1 to id2, the id changes from display to not display, and then changes to display
2. When the mouse moves from id2 to id1, the display of id2 becomes non-display, and then becomes display
What I want is that when the mouse moves on id1 or id2, id2 will keep showing up without changing.
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script><div id="id1"><div id="id2"></div></div><script type="text/javascript">$("#id1").mouseover(function(){$(this).children().fadeIn(1000);}).mouseout(function(){$(this).children().fadeOut(1000);});</script>Problem solution
The initial problem analysis was that when the mouse moved from id1 to id2, the mouse left from id2 to id1, and a mouseout event was triggered for id1, so the display of id2 became non-display. Then the mouse moved to id2, and a mouseover event was triggered on id2. Due to the bubble mechanism, before the mouseover on id2 bubbled to id1, the mouseover event on id1 was triggered, and then id2 changed from non-display to display. Similarly, when the mouse moves from id2 to id1, a mouseout event is triggered for id2. Or is it because of the bubble mechanism that the mouseout event is transmitted to id1, and id2 changes from display to non-display. Then before the mouse moves to id1, a mouseover event is triggered, and then id2 does not display to display.
It seems that the above problem needs to be solved by blocking the mouse out of id1 when the mouse moves from id1 to id2; when the mouse moves from id2 to id1, blocking the mouse out of id2 from id2 to id1, preventing the mouse out of id2 from bubbled above id1. Then the problem cannot be solved just by preventing bubbles.
To solve such problems, jQuery provides mouseenter and mouseleave methods. So the JS code is changed to the following, which solved the problem very well.
$("#id1").mouseenter(function(){$(this).children().fadeIn(1000);}).mouseleave(function(){$(this).children().fadeOut(1000);});Many places introduce mouseenter, mouseleave, mouseover, and mouseout, so I copied and pasted one.
/******************************************************/
1.mouseover and mouseenter
The mouseover event is triggered regardless of whether the mouse pointer passes through the selected element or its child element.
The mouseenter event will only be triggered when the mouse pointer passes through the selected element.
2.mouseout and mouseleave
The mouseout event will be triggered regardless of whether the mouse pointer leaves the selected element or any child element.
The mouseleave event will only be triggered when the mouse pointer leaves the selected element.
/******************************************************/
The phenomenon is indeed this phenomenon, but the process is a bit vague. My understanding is as follows:
When the mouse pointer moves to the selected element, the mouseover event will be triggered. Everyone knows that when the mouse pointer moves from the selected element to its child element, the mouseout event of the selected element will be triggered first, and then the mouseover event of the child element will be bubbled to the selected element. At this time, it is equivalent to the selected element first executing a mouseout event and then executing a mouseover event.
For verification, change the code to the following
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script><div id="id1"><div id="id2"></div></div><script type="text/javascript">$("#id1").mouseover(function(){//$(this).children().fadeIn(1000);console.log('a');}).mouseout(function(){//$(this).children().fadeOut(1000);console.log('b');});</script>Move the mouse from the page to id1, then move from id1 to id2, the console output is as follows
It can be seen that id1 has called mouseover, mouseout, and mouseover events, which are exactly the same as the one analyzed above.
Mouseenter and mouseleave implementation analysis
Principle analysis
From the above analysis, we can see that to achieve the effect of mouseenter and mouseleave, when the mouse moves from the selected element to its child element, the selected element does not execute the mouseout event, nor does it execute the mouseover event that the subclass bubbles. When the mouse moves from the selected element child element to the selected element, the selected element does not execute the mouseover event, nor does it execute the mouseout event that the subclass bubbles.
To achieve the above effect, we need an attribute relatedTarget of the event object, which is used to judge the attributes of the related nodes of the mouseover and mouseout event target nodes. Simply put, when the mouseover event is triggered, the relatedTarget attribute represents the node that the mouse has just left, and when the mouseout event is triggered, it represents the object that the mouse moves to. Since MSIE does not support this property, it has substituted properties, namely fromElement and toElement. In addition, we also need the contains method to determine whether an object is contained in another object.
In this way, when the mouse moves, you need to judge the following two
1. Call mouseover, you only need to determine whether the relatedTarget is a child element of the selected element. If so, it will not be executed (when moving from the selected element child element to the selected element, mouseover will not be executed; when moving from the selected element to the selected element child element, bubbled mouseover will not be executed);
2. Call mouseout, you only need to determine whether the child element of the relatedTarget is selected. If so, it will not be executed (when moving from the selected element child element to the selected element, the mouseout bubbled from the child element is not executed; when moving from the selected element to the selected element child element, the mouseover is not executed);
Implementation process
Determine whether there is an inclusion relationship between two elements
The contains function is encapsulated in jquery as follows
It can be simplified to the following
//Judge whether the two a contains bfunction contains(a,b){return a.contains? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);}Introduction to compareDocumentPosition
This method is part of the DOM Level 3 specification, allowing you to determine the mutual position between the 2 DOM Nodes. This method is more powerful than .contains(). One possible application of this method is to sort DOM Nodes into a detailed and precise order. The information returned by NodeA.compareDocumentPosition(NodeB) is described as follows:
Bit number meaning
Through the above we can understand why we should write it as a.compareDocumentPosition(b) & 16 because if node A contains node B, 16 will be returned, 16&16=1 will be returned, and the results will be 0 in other cases.
Get relatedTarget for compatibility
In order to be compatible with various browsers, refer to the jquery source code, write the following code to obtain the attributes relatedTarget of the mouseover and mouseout event target nodes.
function getRelated(e){var related;var type=e.type.toLowerCase();//Get the event name here if(type=='mouseover'){related=e.relatedTarget||e.fromElement}else if(type='mouseout'){related=e.relatedTarget||e.toElement}return related; }Improve mouseover and mouseout
Improve mouseover and mouseout to achieve improved mouseenter and mouseleave effects, all codes are as follows.
<!DOCTYPE html><html><head><title></title></head><body><div id="id1"><div id="id2"></div></div><script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script><script type="text/javascript">//Judge whether two a contains bfunction contains(a,b){return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);}function getRelated(e){var related;var type=e.type.toLowerCase();//Get the event name here if(type=='mouseover'){related=e.relatedTarget||e.fromElement}else if(type='mouseout'){related=e.relatedTarget||e.toElement}return related; }$(function(){$("#id1").mouseover(function(e){//Defend where the mouse moves to id1 var related=getRelated(e); //If related is the child element id2 of id1, that is, it moves from child element id2 to id1, or it is related to id1, that is, it moves from id1 to its child element id2, then no operation is performed, otherwise the corresponding operation is performed if(this!=related && !contains(this, related)){console.log('mouseover');}}).mouseout(function(e){//Judge where the mouse should move from id1? var related=getRelated(e); //If related is id1, that is, when id1 moves from its child element to id1, or it is related to id2, that is, it moves from id1 to its child element, no operation is performed, otherwise the corresponding operation is performed if(this !=related && !contains(this, related)){console.log('mouseout');}});});</script></body></html>Test, mouse movement route as shown in the following diagram
As can be seen from the console, mouseover and mouseout at this moment have fully equipped mouseenter and mouseleave effects.
Encapsulation of code
If you need to load Jquery or write many representatives every time you perform such an operation, it will be a tedious task. In order to facilitate future operations, appropriate packaging is carried out, simulated Jquery, and generate your own mouseenter and mouseleave. The code is encapsulated into the dqMouse.js file, as follows:
(function(w){var dqMouse = function(obj) {// Function body return new dqMouse.fn.init(obj);}dqMouse.fn = dqMouse.prototype = {// Extended prototype object obj:null,dqMouse: "1.0.0",init: function(obj) {this.obj=obj;return this;},contains:function(a,b) {return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16);},getRelated:function(e) {var related;var type=e.type.toLowerCase();//Get the event name here if(type=='mouseover'){related=e.relatedTarget||e.fromElement}else if(type='mouseout'){related=e.relatedTarget||e.toElement}return related; },over:function(fn){var obj=this.obj;var _self=this;obj.onmouseover=function(e){ var related=_self.getRelated(e); if(this!=related && !_self.contains(this,related)){fn();}} return _self;},out:function(fn){var obj=this.obj;var _self=this;obj.onmouseout=function(e){var related=_self.getRelated(e); if(obj!=related && !_self.contains(obj, related)){fn();}} return _self;}} dqMouse.fn.init.prototype = dqMouse.fn;window.dqMouse = window.$$= dqMouse;})(window);The source file called is as follows:
<div id="id1"><div id="id2"></div></div><script type="text/javascript" src="dqMouse.js"></script><script type="text/javascript">var id1=document.getElementById('id1');$$(id1).over(function(){console.log('mouseover');}).out(function(){console.log('mouseout');}); </script>The above is the relevant content about how to solve the problem of mouseover and mouseout triggering multiple times in JS that the editor introduced to you. I hope it will be helpful to everyone!