打印

BT9017: 只有 IE 支持 mouseenter 和 mouseleave 事件

作者:蔡美纯 钱宝坤

标准参考

问题描述

在 IE 中,用户将鼠标移入移出某对象时,触发 mouseenter 和 mouseleave 事件。
此事件不会冒泡。

造成的影响

只有 IE6 IE7 IE8 浏览器支持 mouseente 和 mouseleave 事件。

受影响的浏览器

Firefox Safari Chrome Opera

问题分析

mouseenter/mouseleave 事件只有 IE 支持。以下为 MSDN 对 mouseenter 的具体解释:

The event fires only if the mouse pointer is outside the boundaries of the object and the user moves the mouse pointer inside the boundaries of the object. If the mouse pointer is currently inside the boundaries of the object, for the event to fire, the user must move the mouse pointer outside the boundaries of the object and then back inside the boundaries of the object.

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.

示例代码

<p id="a">...</p>
<script>
document.getElementById('a').onmouseenter=function(){this.innerHTML="mouseenter fired"}
document.getElementById('a').onmouseleave=function(){this.innerHTML="mouseleave fired"}
</script>

将鼠标移到 P 元素内,仅在 IE6 IE7 IE8 中,P 元素内的文字会改变。

相比 DOM 规范中的 mouseout 和 mouseover 连个事件 IE 的 mouseenter 和 mouseleave 事件不会在鼠标移入移出容器内其他子标记时触发相应事件。

具体实例可以参见下方的测试页面——当鼠标移入灰色子元素时会触发mouseout 和 mouseover 事件,但是 IE 专有事件模型则没有这个问题。

解决方案

1. 避免使用 mouseenter 和 mouseleave 事件。
2. 在非 IE 浏览器中模拟这两个事件。如:res.html

<!DOCTYPE html>
<html>
<head>
<script>
  window.onload = function (){
    var ua = navigator.userAgent;
    Test = {
      version: (ua.match(/.+(?:rv|it|ra|ie|me)[\/: ]([\d.]+)/i)||[])[1],
      ie: /msie/i.test(ua) && !/opera/i.test(ua),
      op: /opera/i.test(ua),
      sa: /version.*safari/i.test(ua),
      ch: /chrome/.test(ua),
      ff: /gecko/i.test(ua) && !/webkit/i.test(ua),
      wk: /webkit/i.test(ua),
      mz: /mozilla/i.test(ua)&&!/(compatible|webkit)/i.test(ua)
    }
    
    function $(id) { return document.getElementById(id); }
    
    function addEvent(el, type, fn){
      (el.attachEvent) ? (el.attachEvent("on" + type, fn)) : (el.addEventListener(type, fn, false));
    };

    var contains = document.compareDocumentPosition
      ? function (parent, child) {
        return !!(parent.compareDocumentPosition(child) & 16);
      }
      : function (parent, child) {
        return child !== child && (parent.contains ? parent.contains(child) : true);
      }

    function fixMouseLeave (elem, fn){
      var mouseleave = Test.ie ? "mouseleave" : "mouseout";
      (elem == null || elem == window ) && (elem = document);
      return {
        type: mouseleave,
        elem: elem,
        fn: Test.ie ? fn : function(e) {
          (contains(e.relatedTarget,this)) && (fn.call(this, e));
        }
      }
    }
    
    function fixMouseEnter (elem, fn){
      var mouseenter = Test.ie ? "mouseenter" : "mouseover";
      (elem==null || elem==window ) && (elem = document);
      return {
        type: mouseenter,
        elem: elem,
        fn: Test.ie ? fn : function(e) {
          (contains(e.relatedTarget,this)) && (fn.call(this ,e));
        }
      }
    }
    
    var me = fixMouseEnter($("a"), function (e) {
      $("b").value += "enter\n";
    });
    var ml = fixMouseLeave($("a"), function (e) {
      $("b").value += "leave\n";
    });
    
    addEvent(me.elem, me.type, me.fn);
    addEvent(ml.elem, ml.type, ml.fn);
  }
</script>
</head>
<body>
  <div id="a" style="background:gold; width:100px; height:100px; padding:30px">
    <div style="background:gray; height:100%;"></div>
  </div>
  <textarea id="b" style="width:100px; height:100px;"></textarea>
</body>
</html>

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6
Chrome 4.0.302.3 dev
Safari 4.0.4
Opera 10.60
测试页面: mouseenter_and_mouseleave.html
res.html
本文更新时间: 2010-08-13

关键字

mouseenter mouseleave