浏览器中模拟mouseenter omouseleave事件(解决onmouseover onmouseout重复调用)

一. mouseenter和mouseleave何时被触发


我们来看下官方解释(mouseentermouseleave):

// onmouseenter:
Fires when the user moves the mouse pointer inside the boundaries of an object.
即:当鼠标移入元素对象的边界之内时,激活该事件

// onmouseleave:
Fires when the user moves the mouse pointer outside the boundaries of the object.
即:当鼠标移出元素对象的边界之外时,激活该事件

二. 与mouseover和mouseout的区别


官方站点在介绍mouseenter和mouseleave时,同时说明了与mouseover和mouseout的不同:

// onmouseenter vs onmouseover
Unlike the onmouseover event, the onmouseenter event does not bubble. In other words, the onmouseenter event does not fire when the user moves the mouse pointer over elements contained by the object, whereas onmouseover does fire.
即:onmouseenter不会冒泡,onmouseover则会,由于这个差异,当鼠标在元素边界内移动时,不会激活onmouseenter(只在鼠标进入元素边界内时激活),但会激活onmouseover(当该元素包含子元素时)。

// onmouseleave vs onmouseout
同上,由于存在冒泡的差异,导致了鼠标在元素边界内移动时,会激活onmouseout(当该元素包含子元素时),但不会激活onmouseleave。

三. 为什么要模拟mouseenter和mouseleave?


原因很简单:相对于mouseover和mouseout,mouseenter和mouseleave具有性能优势(不会反复触发),但只有IE支持它。。。


四. 如何模拟?


原理:监听目标元素的mouseover和mouseout事件,只当鼠标移入目标元素时,才执行回调函数,忽略子元素上激活的mouseover和mouseout事件。我们通过事件对象的relatedTarget (ie浏览器为fromElement或toElement)属性,来判断鼠标是移入/移出目标元素,还是在目标元素内移动:


(1) 当mouseover被激活时,relatedTarget表示鼠标进入目标元素时,是从哪个元素离开的,我们可以对relatedTarget的值进行判断:如果值不是目标元素,也不是目标元素的子元素,就说明鼠标已移入目标元素;


(2) 当mouseout被激活时,relatedTarget表示鼠标离开目标元素时,进入了哪个元素,我们同样可以对relatedTarget的值进行判断:如果值不是目标元素,也不是目标元素的子元素,就说明鼠标已移出目标元素;

 

 

五. 实例

// HTML:
<ul id="J_List">
   <li><a href="#">item1</a></li>
   <li><a href="#">item2</a></li>
   <li><a href="#">item3</a></li>
</ul>
// JS(基于YUI):
<script type="text/javascript">
   var Y = YAHOO.util,
        Dom = Y.Dom,
        Event = Y.Event;

   // 获取所有的li
   var oList = Dom.get('J_List');

   Event.on(oList, 'mouseover', function(e) {
        var rt = Event.getRelatedTarget(e),
             curElem = this;

        // 如果rt不是curElem且不是curElem的子元素, 则就是mouse enter的情况
        if (rt !== curElem && !Dom.isAncestor(curElem, rt)) {
             console.log('enter: ' + curElem.id);
        }
    });

    Event.on(oList, 'mouseout', function(e) {
         var rt = Event.getRelatedTarget(e),
              curElem = this;

         // 如果rt不是curElem且不是curElem的子元素, 则就是mouse leave的情况
         if (rt !== curElem && !Dom.isAncestor(curElem, rt)) {
              console.log('leave: ' + curElem.id);
         }
    });
</script>
原文地址:https://www.cnblogs.com/wuwenjie/p/5576723.html