【问题标题】:How to emulate mouseenter and mouseleave DOM events for old browsers?如何模拟旧浏览器的 mouseenter 和 mouseleave DOM 事件?
【发布时间】:2014-08-01 19:34:55
【问题描述】:

用 div 创建一个窗口并使用 mouseover - mouseout 有一个已知问题:如果里面有一个子 div,它会触发 mouseout。最近由 mouseenter 和 mouseleave 解决了这个问题,因为除非鼠标点离开根 div(真正的窗口),否则不会触发。不幸的是,有很多浏览器无法识别这些新事件,如this article 所示。 :

  • 火狐7
  • 铬 14
  • Safari 5.1

我认为可以使用 mouseover 和 mouseout 的事件冒泡处理来产生所需的效果。是否可以?还有另一种(更好的)方法吗?还是根本做不到?

Obs.:在这个项目中没有使用 jQuery。

编辑:我的测试代码:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Mouse Events Tester</title>
<script>
var inside = function(e){
    console.log("I am inside!");
}

var outside = function(e){
    if(e.target !== this) console.log("Now outside...");
}

function targetOnly(handler) {
    return function (e) {
        if (e.target === this)
            return handler.apply(this, arguments);
        return;
    };
}

function ini(){
    document.getElementById("win").addEventListener("mouseover", inside, false);
    document.getElementById("win").addEventListener("mouseout", outside, false);
}


</script>
</head>

<body onload="ini();">
<div id="win" style="border:#000 solid 2px; background-color:#999;">
    <p>Window</p>
    <div id="anything" style="border:#000 dashed 1px; background-color:#CCC;">
    <p>An object inside the window</p>
    </div>
</div>
</body>
</html>

【问题讨论】:

  • 查看e.target并与this比较,如果e.target !== this,则事件来自子节点
  • 你有理由支持这些旧浏览器吗?
  • @JamesMontagne:我正在使用 Safari 5.1 进行开发,列表中的东西对我有用,对吧?
  • @PaulS.:有趣!你为什么不发布答案?

标签: javascript events mouseevent


【解决方案1】:

我花了大约一个小时的时间,得到了这段代码:

Element.prototype.childOf = function(p){var c=this;while((c=c.parentNode)&&c!==p);return !!c};

el = document.getElementById('your-element-id');

el.onmouseover = function(e) {
    if (e.target == e.currentTarget && !e.fromElement.childOf(e.currentTarget) && !e.toElement.childOf(e.currentTarget)) {
        // you are in
    }
}

el.onmouseout = function(e) {
    if (e.target == e.currentTarget && !e.fromElement.childOf(e.currentTarget) && !e.toElement.childOf(e.currentTarget)) {
        // you are out
    }
}

【讨论】:

  • 它接缝可以完成这项工作。我会等待其他答案,因为我提到了气泡,让我们看看是否有人有话要说。
  • @GustavoPinent Capturing 和 Bubbling 只是代表事件传播的方向,与此类问题无关...
  • 我今天早上测试了,它有一个有趣的效果:当进入一个内部 div(上一级)时,它没有触发,但是当它回到根 div 时,它触发(并且它不应该)。我认为解决方案会复杂一些。
  • 通过以下方式改变你的表达方式:“!(e.target.id==e.currentTarget.id)”已经解决了一半的问题。当鼠标从内部 DIV 回来时,它仍然会触发,但是,鼠标悬停也会触发,因此可以对其进行管理。您可以尝试修复您的答案。
  • @GustavoPinent 我编辑了我的代码,我想要为此获得奖励,因为我真的浪费了一个小时试图达到这个结果,啊哈哈。现在可以了。
【解决方案2】:

使用event.target,您可以看到一个事件 e 来自哪个节点。如果您需要经常检查这样的事情,那么编写一个函数包装器可能最简单,它只在e.target === this 时调用您的handler

function targetOnly(handler) {
    return function (e) {
        if (e.target === this)
            return handler.apply(this, arguments);
        return;
    };
}

foo.addEventListener('mouseover', targetOnly(handerA));
foo.addEventListener('mouseout' , targetOnly(handerB));

event.target here 的 MDN 页面

【讨论】:

    【解决方案3】:

    使用 display:none 添加一个不可见的 div 作为子级,当触发鼠标悬停时,显示不可见的 div,用不可见的 div 触发 mouseout, 像这样的。

        <div id="parent" onmouseover="functionover()" >
            <div id="child1" onmouseout="functionout()"
             style='position:absolute;display:none;width:100%;height:100%;'"></div>
            <div id="yourchildelement" ></div>
        </div>
    
        <script>
        function functionover()
        {
        $('#child1').css('display','block');
        ....
        }
        </script>
    

    类似的,希望对你有帮助...

    【讨论】:

    • 我没有在这个项目中使用 jQuery。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-13
    • 2016-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多