【转载】mouseover多次触发叠加问题

作者:ltx851201

js当中mouseover和mouseout多次触发(非冒泡)

JS当中,mouseover和mouseout多次触发事件,不光是冒泡会产生,就是不冒泡,在一定条件下 ,也会产生多次触发事件;

例如下面的结构的情况下,我在class="ceng_up feature_tips"这个层上加这两个事件,就会多次触发mouseover和mouseout而不断的交替事件。

  1. <div id="tip_popu">  
  2.     <!--浮动层-->  
  3.     <div class="ceng_up feature_tips" style="top:4px; left:9px;">  
  4.         <div class="top_feature"><div class="inner_text"><img src="/themes/default/images/icon.gif"><a href="#" class="em_a">武林英雄</a></div><div class="jishu">5426</div></div>  
  5.         <div class="xiaceng">  
  6.             <a class="c_1" href="#"></a>  
  7.             <a class="c_2" href="#"></a>  
  8.             <a class="c_3" href="#" title="活动公告"></a>  
  9.             <div class="benzhou">本周<font color="#FF0000">+5%</font></div>  
  10.         </div>  
  11.     </div>  
  12.     <div style="top:35px; left:239px; " class="ceng_down feature_tips">  
  13.         <div class="top_feature"><div class="inner_text"><img src="/themes/default/images/icon.gif"><a href="#" class="em_a">武林英雄</a></div><div class="jishu">5426</div></div>  
  14.         <div class="xiaceng">  
  15.             <a href="#" class="c_1"></a>  
  16.             <a href="#" class="c_2"></a>  
  17.             <a title="活动公告" href="#" class="c_3"></a>  
  18.             <div class="benzhou">本周<font color="#3A9B00">-9%</font></div>  
  19.         </div>  
  20.     </div>  
  21. </div>  


开始是搞了好久,都没有找到适合的方法处理这个问题,最后终于在一个BLOG上看到这样的一个说法,终于把这个问题解决了;

下面是那个BLOG的原话,哥们直接复制过来了,加的颜色区分一下:

在用到mouseover和mouseout事件来作为事件触发的条件,但是如果我们用做触发的元素内部有其他的元素的时候当鼠标移上的时候会反复的触发mouseover和mouseout事件。因为内部元素在鼠标移上的时候会向它的父对象派发事件,所以外面元素相当于也触发了mouseover 事件。 

    为了阻止mouseover和mouseout的反复触发,这里要用到event对象的一个属性relatedTarget,这个属性就是用来判断 mouseover和mouseout事件目标节点的相关节点的属性。简单的来说就是当触发mouseover事件时,relatedTarget属性代表的就是鼠标刚刚离开的那个节点,当触发mouseout事件时它代表的是鼠标移向的那个对象。由于MSIE不支持这个属性,不过它有代替的属性,分别是 fromElement和toElement。

    有了这个属性,我们就能够清楚的知道我们的鼠标是从哪个对象移过来,又是要移动到哪里去了。这样我们就能够通过判断这个相关联的对象是否在我们要触发事件的对象的内部,或者是不是就是这个对象本身。通过这个判断我们就能够合理的选择是否真的要触发事件。

    这里我们还用到了一个用于检查一个对象是否包含在另外一个对象中的方法,contains方法。MSIE和FireFox分别提供了检查的方法,这里封装了一个函数。

 

 

function contains(parentNode, childNode) { if (parentNode.contains) { return parentNode != childNode && parentNode.contains(childNode); } else { return !!(parentNode.compareDocumentPosition(childNode) & 16); } }

 

    这个函数用于检查一个对象是否被包含在我们的触发对象里面。

    下面就是我们的重点了,我封装了一个用于检查鼠标是否真正从外部移入或者移出对象的函数checkHover(e,target),这个函数需要传入当前的事件对象和目标对象。

function checkHover(e,target){ if (getEvent(e).type=="mouseover") { return !contains(target,getEvent(e).relatedTarget||getEvent(e).fromElement) && !((getEvent(e).relatedTarget||getEvent(e).fromElement)===target); } else { return !contains(target,getEvent(e).relatedTarget||getEvent(e).toElement) && !((getEvent(e).relatedTarget||getEvent(e).toElement)===target); } }function getEvent(e){ return e||window.event; }

    函数里面用到的getEvent()函数用于在MSIE或者FF下返回一个可用的event对象,这里你可以自己封装成别的函数。

    函数的逻辑很简单,首先判断事件的类型,这个主要是为了迁就MSIE,当是mouseover的时候relatedTarget在MSIE下应该是 fromElement,而mouseout则应该返回toElement,当然在FF下面就好办了,都是同一个属性relatedTarget。首先判断我们的relatedTarget是否在目标对象的内部,如果是的话则直接返回假如果不在内部的话则判断是否是目标对象本身,如果是的话返回假,要是两种情况都不成立则返回真。

    到这里我们的主要工作做完了,有了这个函数我们在进行编程的时候只要在mouseover或者mouseout事件内部先检查一下,再进行下一步操作就能轻松实现hover的效果。

myElement.onmouseover=function(e){ if(checkHover(e,this)){ do someting... } } myElement.onmouseout=function(e){ if(checkHover(e,this)){ do someting... } }

 

下面的代码,则是哥们自己写的代码部分,也贴出来,供大家参考(基于jquery):

 

[javascript] view plaincopyprint?
 
    1. //取得当前窗口的事件  
    2. var e = window.event;  
    3. $('.con_yx ul li img').live(  
    4.         'mouseover',  
    5.         function(e) {  
    6.             if(checkHover(e,this)){  
    7.                 var con_yx = $('.con_yx');  
    8.                 var index = con_yx.index($(this).parent().parent().parent());// 100px;  
    9.                 $('#index_val').val(index);  
    10.                 var currentspan = $(this).parent().find('span');// down  
    11.                 var position = $(this).offset();  
    12.                 if (currentspan.hasClass('up')) {  
    13.                     $(this).parent().find('img,.em_a').clone().appendTo('.ceng_up .inner_text');  
    14.                     $('.ceng_up').css('top', (position.top - 5));  
    15.                     $('.ceng_up').css('left', (position.left - 5));  
    16.                     $('.ceng_up').css('z-index',9999);  
    17.                     $('.ceng_down').hide();  
    18.                     $('.ceng_up').show();  
    19.                 } else {  
    20.                     $(this).parent().find('img,.em_a').clone().appendTo('.ceng_down .inner_text');  
    21.                     $('.ceng_down').css('top', (position.top - 5));  
    22.                     $('.ceng_down').css('left', (position.left - 5));  
    23.                     $('.ceng_down').css('z-index',9999);  
    24.                     $('.ceng_up').hide();  
    25.                     $('.ceng_down').show();  
    26.                 }  
    27.             }  
    28. });  
    29. //鼠标移除层区域后,触发mouseout事件,把整个层隐藏  
    30. $('.ceng_up,.ceng_down').live('mouseout'function(e) {  
    31.     if(checkHover(e,this)){  
    32.         $(this).find('.inner_text').html('');  
    33.         $(this).hide();  
    34.     }  
    35. });  
    36.   
    37. /** 
    38.  * 下面是一些基础函数,解决mouseover与mouserout事件不停切换的问题(问题不是由冒泡产生的) 
    39.  */  
    40. function checkHover(e, target) {  
    41.     if (getEvent(e).type == "mouseover") {  
    42.         return !contains(target, getEvent(e).relatedTarget  
    43.                 || getEvent(e).fromElement)  
    44.                 && !((getEvent(e).relatedTarget || getEvent(e).fromElement) === target);  
    45.     } else {  
    46.         return !contains(target, getEvent(e).relatedTarget  
    47.                 || getEvent(e).toElement)  
    48.                 && !((getEvent(e).relatedTarget || getEvent(e).toElement) === target);  
    49.     }  
    50. }  
    51.   
    52. function contains(parentNode, childNode) {  
    53.     if (parentNode.contains) {  
    54.         return parentNode != childNode && parentNode.contains(childNode);  
    55.     } else {  
    56.         return !!(parentNode.compareDocumentPosition(childNode) & 16);  
    57.     }  
    58. }  
    59. //取得当前window对象的事件  
    60. function getEvent(e) {  
    61.     return e || window.event;  

 

jQuery因mouseover,mouseout冒泡产生的闪烁问题

由于浏览器的冒泡行为。造成如果在一个DIV元素上同时定义了mouseover,mouseout的时候,当鼠标移动到DIV中的child子元素的时候,就会同时执行了两个操作mouseover和mouseout。

解决方案:阻止冒泡行为,当执行mouseover的时候不触发mouseout的操作。

 

方法1:
延迟执行(setTimeout)、取消延迟(clearTimeout),就是当mouseout的时候延迟执行,而在mouseover的时候取消延迟执行。当鼠标在DIV上边移动的时候因为延迟的执行所以mouseout一直都不会被触发。

[javascript] view plaincopyprint?
 
  1. $('div').mouseout(function(){  
  2.      clearTimeout(t);  
  3.       t=setTimeout(zoomIn,400);  
  4.     }).mouseover(function(){  
  5.    if(t!=null)clearTimeout(t);  
  6.    t=null;  
  7.   }  
  8. );   

 

方法2:jquery(需要版本号大于1.2.2)
mouseenter和mouseleave事件IE特有的函数,使用jquery就很好的解决了兼容问题。函数的原理当第一次鼠标进入节点区域时触发,以后在节点区域内(子节点间)移动时不触发。

[javascript] view plaincopyprint?
 
  1. $('div').bind("mouseenter",function(){  
  2. // do something on mouseenter  
  3. });  
  4. $('div').bind("mouseleave",function(){  
  5. // do something on mouseleaver  
  6. });   

 

jquery版本 >1.4简化写法:

[javascript] view plaincopyprint?
 
  1. $('div').bind({  
  2. mouseenter:function(){  
  3. // do something on mouseenter  
  4. },  
  5. mouseleaver:function(){  
  6. // do something on mouseleaver  
  7. }  
  8. })  

 

posted on 2013-11-12 15:22  meeming  阅读(217)  评论(0)    收藏  举报



Fork me on GitHub