您好,欢迎访问一九零五行业门户网

JavaScript中mouseover和mouseout多次触发解决办法

问题描述
我希望当鼠标移动到id1上的时候,id2显示,当鼠标离开id1的时候,id2显示。问题如下:
1.当鼠标从id1上移动到id2上的时候,id由有显示变为不显示,然后变为显示
2.当鼠标从id2上移动到id1上的时候, id2有显示变为不显示,然后变为显示
我希望的是当鼠标在id1或者id2上移动的时候,id2一直显示,不发生变化。
<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>
问题解决办法最开始的问题分析,当鼠标从id1上移动到id2上的时候,由于鼠标由id2离开进入id1,针对id1触发了一个mouseout事件,于是id2有显示变为不显示,接着在鼠标移动到id2上,在id2上触发了一个mouseover事件,由于冒泡机制,id2上的mouseover冒泡到id1之前,触发了id1上的mouseover事件,然后id2由不显示变为显示。同理,当鼠标从id2上移动到id1上的时候,针对id2,触发了一个mouseout事件,还是因为冒泡机制,mouseout事件传到id1上,id2由显示变为不显示,接着鼠标移动到id1之前,触发了一个mouseover事件,然后id2有不显示变为显示。
看来,上面的问题归根要解决的是,当鼠标由id1上移动到id2上的时候,阻止id1的mouseout事件;当鼠标从id2上移动到id1上的时候,阻止id2的mouseout事件冒泡到id1之上。那么仅仅通过阻止冒泡是解决不了问题。
为了解决这样的问题,jquery提供了mouseenter和mouseleave方法。于是将js代码改为如下,很好解决了问题。
$("#id1").mouseenter(function(){ $(this).children().fadein(1000); }).mouseleave(function(){ $(this).children().fadeout(1000); });
很多地方都有介绍mouseenter、mouseleave与mouseover、mouseout,于是复制粘贴了一个。
/*********************************************************/
1.mouseover与mouseenter
不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件。
只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件。
2.mouseout与mouseleave
不论鼠标指针离开被选元素还是任何子元素,都会触发 mouseout 事件。
只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。
/*********************************************************/
现象确实是这个现象,但是过程说的有点模糊,我的理解如下:
当鼠标指针移动到被选元素,会触发 mouseover 事件,这个大家都知道,当鼠标指针由被选元素移动到其子元素,先是触发被选元素的mouseout事件,然后子元素的mouseover事件冒泡到被选元素,此时相当于被选元素先执行了一个mouseout事件,然后执行了一个mouseover事件。
为了验证将代码改为如下
<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>
鼠标从页面移动到id1,然后由id1移动到id2上,控制台输出如下图
可以看出id1先后调用了mouseover、mouseout、mouseover事件,正好和上面分析的相同。
mouseenter与mouseleave实现分析原理分析从上面分析,我们可以看出,要实现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); }
comparedocumentposition介绍这个方法是 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。
获取兼容性性的relatedtarget为了兼容各种浏览器,参考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改进mouseover和mouseout以实现改进mouseenter与mouseleave效果,所有代码如下。
<!doctype html><html><head> <title></title></head><body> <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="https://code.jquery.com/jquery-1.12.4.js"></script> <script type="text/javascript"> //判断两个a中是否包含b function 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();//这里获取事件名字 if(type=='mouseover'){ related=e.relatedtarget||e.fromelement }else if(type='mouseout'){ related=e.relatedtarget||e.toelement } return related; } $(function(){ $("#id1").mouseover(function(e){ //判断鼠标从哪移到id1上面 var related=getrelated(e); //如果related是id1的子元素id2,即从子元素id2移动到id1,或是related为id1,即从id1移动到其子元素id2上面,则不进行任何操作,否则进行相应的操作 if(this!=related && !contains(this,related)){ console.log('mouseover'); } }).mouseout(function(e){ //判断鼠标要从id1上面移动到哪去? var related=getrelated(e); //如果related是id1,即当id1从其子元素移动到id1上,或是related是id2,即从id1上移动到其子元素,不进行任何操作,否则进行相应的操作 if(this !=related && !contains(this,related)){ console.log('mouseout'); } }); }); </script></body></html>
测试,鼠标移动路线如下图路线
由控制台可以很看出,此刻的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多次触发解决办法 的内容。
其它类似信息

推荐信息