Home > Article > Web Front-end > Solution to multiple triggering of mouseover and mouseout in JavaScript
I hope that when the mouse moves to id1, id2 will be displayed, and when the mouse leaves id1, id2 will be displayed. The problem is as follows:
1. When the mouse moves from id1 to id2, the id changes from displayed to not displayed, and then to displayed
2. When the mouse moves from id2 to id1, id2 changes from being displayed to not being displayed, and then to being displayed
What I hope is that when the mouse moves on id1 or id2, id2 will always be displayed without changing.
<script type="text/javascript" src=" </script><p id="id1" style="width:800px; height:400px; background-color:#F23"> <p id="id2" style="width:400px; height:300px; background-color:#0F8; display:none;"> </p> </p><script type="text/javascript"> $("#id1").mouseover(function(){ $(this).children().fadeIn(1000); }).mouseout(function(){ $(this).children().fadeOut(1000); });</script>
The initial problem analysis, when the mouse moves from id1 to id2, because the mouse leaves from id2 and enters id1 , a mouseout event is triggered for id1, so id2 is displayed but not displayed. Then when the mouse moves to id2, a mouseover event is triggered on id2. Due to the bubbling mechanism, the mouseover on id2 bubbles up before id1. The mouseover event on id1 is triggered, and then id2 changes from not displayed to displayed. In the same way, when the mouse moves from id2 to id1, a mouseout event is triggered for id2. Or because of the bubbling mechanism, the mouseout event is transmitted to id1, id2 changes from displayed to not displayed, and then the mouse moves to id1. Before, a mouseover event was triggered, and then id2 changed from not displayed to displayed.
It seems that the ultimate solution to the above problem is to prevent the mouseout event of id1 when the mouse moves from id1 to id2; when the mouse moves from id2 to id1, prevent id2 The mouseout event bubbles up to id1. Then simply preventing bubbling will not solve the problem.
In order to solve this problem, Jquery provides mouseenter and mouseleave methods. So I changed the JS code to the following, which solved the problem very well.
$("#id1").mouseenter(function(){ $(this).children().fadeIn(1000); }).mouseleave(function(){ $(this).children().fadeOut(1000); });
Many places have introduced mouseenter, mouseleave, mouseover, and mouseout, so I copied and pasted one.
/**************************************** **********************/
1.mouseover and mouseenter
No matter the mouse pointer passes through the selected element or Its child elements will trigger the mouseover event.
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 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. As we all know, when the mouse pointer moves from the selected element to its sub-element, the mouseout event of the selected element is first triggered, and then the mouseover event of the sub-element is triggered. The event bubbles up to the selected element, which is equivalent to the selected element first executing a mouseout event and then executing a mouseover event.
In order to verify, change the code to the following
<script type="text/javascript" src=" </script><p id="id1" style="width:800px; height:400px; background-color:#F23"> <p id="id2" style="width:400px; height:300px; background-color:#0F8; position:absolute; top:300px;"> </p> </p><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, and then move from id1 to id2. The console output is as follows
You can see id1 The mouseover, mouseout, and mouseover events are called successively, which is exactly the same as analyzed above.
从上面分析,我们可以看出,要实现mouseenter与mouseleave的效果,就是当鼠标从被选元素移动到其子元素上的时候,被选元素不执行mouseout事件,也不执行子类冒泡过来的mouseover事件,当鼠标从被选元素子元素移动到被选元素上的时候,被选元素不执行mouseover事件,也不执行子类冒泡过来的mouseout事件。
要实现上面的效果,我们需要event对象的一个属性relatedTarget,这个属性就是用来判断 mouseover和mouseout事件目标节点的相关节点的属性。简单的来说就是当触发mouseover事件时,relatedTarget属性代表的就是鼠标刚刚离开的那个节点,当触发mouseout事件时它代表的是鼠标移向的那个对象。由于MSIE不支持这个属性,不过它有代替的属性,分别是 fromElement和toElement。除此,我们还需要contains方法,来判断一个对象是否包含在另外一个对象中。
这样当鼠标移动,需要判断以下两条即可
1.调用mouseover,只需要判断relatedTarget是否被选元素的子元素,如果是,则不执行(当于从被选元素子元素移动到被选元素,不执行mouseover;当于从被选元素移动到被选元素子元素,不执行冒泡过来的mouseover);
2.调用mouseout,只需要判断relatedTarget是否被选元素的子元素,如果是,则不执行(当于从被选元素子元素移动到被选元素,不执行子元素冒泡过来的mouseout;当于从被选元素移动到被选元素子元素,不执行mouseover);
jquery中封装了contains函数如下
可以简化为如下
//判断两个a中是否包含b function contains(a,b){ return a.contains ? a != b && a.contains(b) :!!(a.compareDocumentPosition(b) & 16); }
这个方法是 DOM Level 3 specification 的一部分,允许你确定 2 个 DOM Node 之间的相互位置。这个方法比 .contains() 强大。这个方法的一个可能应用是排序 DOM Node 成一个详细精确的顺序。NodeA.compareDocumentPosition(NodeB)返回的信息描述如下:
比特 | 序号 | 意义 |
---|---|---|
000000 | 0 | 元素一致 |
000001 | 1 | 节点在不同的文档(或者一个在 文档之外) |
000010 | 2 | 节点 B 在节点 A 之前 |
000100 | 4 | 节点 A 在节点 B 之前 |
001000 | 8 | 节点 B 包含节点 A |
010000 | 16 | 节点 A 包含节点 B |
100000 | 32 | 浏览器的私有使用 |
通过上面我们就可以理解为什么要写成a.compareDocumentPosition(b) & 16因为如果节点 A 包含节点 B,就会返回16,16&16=1,其他的情况结果都会0。
为了兼容各种浏览器,参考jquery源码,写出如下代码,来获取mouseover和mouseout事件目标节点的相关节点的属性relatedTarget。
function getRelated(e){ var related; var type=e.type.toLowerCase();//这里获取事件名字 if(type=='mouseover'){ related=e.relatedTarget||e.fromElement }else if(type='mouseout'){ related=e.relatedTarget||e.toElement } return related; }
改进mouseover和mouseout以实现改进mouseenter与mouseleave效果,所有代码如下。
测试,鼠标移动路线如下图路线
由控制台可以很看出,此刻的mouseover和mouseout已经完全具备mouseenter与mouseleave效果效果。
代码的封装
如果每次进行这样的操作,都需要加载Jquery或是写很多代码,将是件繁琐的事,为了便于以后操作,进行了适当的封装,模拟Jquery,生成自己的mouseenter与mouseleave。代码封装到dqMouse.js文件中,如下:
(function(w){ var dqMouse = function(obj) { // 函数体 return new dqMouse.fn.init(obj); } dqMouse.fn = dqMouse.prototype = { // 扩展原型对象 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();//这里获取事件名字 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);
调用的源文件如下:
<p id="id1" style="width:800px; height:400px; background-color:#F23"> <p id="id2" style="width:400px; height:300px; background-color:#0F8; position:absolute; top:300px;"> </p> </p> <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>
经过测试okey。
以上就是JavaScript中mouseover和mouseout多次触发解决办法 的内容,更多相关内容请关注PHP中文网(www.php.cn)!