JS中mouseover和mouseout多次触发问题如何解决(2)

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)返回的信息描述如下:

比特 序号 意义

JS中mouseover和mouseout多次触发问题如何解决

通过上面我们就可以理解为什么要写成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> <div> <div> </div> </div> <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);

调用的源文件如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzpywj.html