14

我想在鼠标离开浏览器窗口时运行一些 Javascript 代码。我只需要支持 Safari (WebKit.)

我尝试在窗口上放置一个 mouseout 处理程序。当鼠标离开浏览器窗口时,该处理程序被可靠地调用。但是由于冒泡,当鼠标在文档中的元素之间移动时也会调用它。我不知道如何确定鼠标何时实际离开窗口以及何时仅在元素之间移动。

当鼠标离开窗口时,恰好会产生一个事件,并且目标元素看起来就是鼠标实际所在的元素。所以检查目标元素是窗口还是文档不起作用。并且将整个页面包装在一个不可见的包含 div 中也不起作用:如果 div 是不可见的,那么鼠标将永远不会在它上面,所以没有任何变化。

(如果我将处理程序放在 document 或 document.body 上,也会发生同样的事情,除了令人惊讶的是 document.body 在鼠标进入或离开窗口的空白部分(例如创建的空白垂直空间)时没有获得 mouseover/mouseout 事件通过绝对定位元素底部:0。对于该空间,文档和窗口将获得鼠标悬停/鼠标退出事件,目标为 <html>,但 document.body 不会。)

我的一些想法:

  • 在每个 mouseout 事件中,获取鼠标的实际位置并查看它是否实际上位于窗口上方。但我不知道这是否真的可行,而且听起来要消除所有的竞争条件会很棘手。
  • 还注册一个鼠标悬停处理程序并检测鼠标悬停未进行(或紧随其后)鼠标悬停的情况。但这需要一个计时器。

我们使用prototype.js 非常理想,我想用原型的Event.observe 来表达解决方案,但我可以弄清楚那部分。

感谢您的任何建议!

4

7 回答 7

12

摘要:这可以通过在 mouseout 事件期间检查 relatedTarget 属性来干净地完成。如果 relatedTarget 不是 document 的子项,则鼠标刚刚离开窗口。自己做很容易,但如果您不想这样做,一些库(Mootools,未来的 Prototype..)具有内置功能,而其他库(当前的 Prototype)具有可用的扩展。在 IE 上,您可以改用 mouseleave,它是 mouseout 的非冒泡版本。

细节:

IE 具有称为 mouseenter 和 mouseleave 的事件,它们是 mouseover 和 mouseout 的非冒泡版本。其他浏览器没有,但如果他们这样做了,在窗口或文档上设置一个 mouseleave 侦听器就可以了。

一位名叫肯斯奈德的绅士前来救援:

在鼠标悬停时,relatedTarget 属性引用指针来自的节点。在 mouseout 时,relatedTarget 属性引用指针所指向的节点。在任何事件中,范围都是事件所附加的节点。当 relatedTarget 不是 currentTarget 的子节点时,mouseover 事件相当于mouseenter 事件和 mouseout 事件等价于 mouseleave 事件。

-- http://kendsnyder.com/archives/6-MouseEnter-and-MouseLeave.html

这使得在其他浏览器中实现 mouseenter 和 mouseleave 成为可能。事实上,Ken 提供了相同的原型代码来执行此操作:http: //kendsnyder.com/sandbox/enterleave/MouseEnterLeave.js

Duroth 在评论中指出 MooTools 已经包含了类似的东西。(感谢 Duroth。)听起来即将发布的 Prototype 版本(1.6.2)可能包含此功能,但我找不到任何确定的东西。

于 2009-11-04T08:42:46.073 回答
10

仅使用 javascript,不使用原型或 jquery 等。

<html>
<head>
<script type="text/javascript">
  var mouseX = 0;
  var mouseY = 0;
  var counter = 0;
var mouseIsIn = true;
function wireEvent() {
window.addEventListener("mouseout",
    function(e){
        mouseX = e.pageX;
        mouseY = e.pageY;
        if ((mouseY >= 0 && mouseY <= window.innerHeight)
        && (mouseX >= 0 && mouseX <= window.innerWidth))
            return;
        //do something for mouse out
        counter++;
        mouseIsIn = false;
        document.getElementById('in_out').innerHTML='out' + counter;
    },
    false);
window.addEventListener("mouseover",
    function(e){
        if(mouseIsIn)
            return;
        //do something for mouse over
        counter++;
        mouseIsIn = true;
        document.getElementById('in_out').innerHTML='in' + counter;
    },
    false);
}
</script> 
</head>
<body onload="wireEvent();">
<div id="in_out">&nbsp;</div>
<div style="width:300px; height: 200px; background: red;">Dummy element</div>
</body>
</html>

更新:添加了在体内移入/移出元素时触发
的鼠标位置检查。mouseout如果它在窗口内,mouseout则不会触发事件。
还引入了一个标志,用于使用mouseIsIn. 如果是truemouseover也不会触发。

于 2009-11-04T07:29:37.353 回答
2

当鼠标离开任何元素(包括窗口)时,窗口对象将触发一个mouseout事件并将该event对象与它一起传递。

事件对象中的一项称为toElement,它是鼠标离开旧元素时刚刚进入的元素的指针。但是当鼠标离开窗口时,没有这样的,toElement所以这个项目变成了null

通过测试此项是否nullmouseout事件上,您可以判断鼠标是否离开了窗口。这是代码:

window.onmouseout=function(event){ 
  if(event.toElement===null) console.log('the mouse left the window'); 
}
于 2014-05-10T02:27:39.947 回答
1

也许您可以为 mouseover 和 mouseout或其他包含整个文档的元素设置一个侦听器,并使用它(通过保存它发生)作为触发器来确定它是否是窗口上的有效 mouseout documentbody

如果做不到这一点,你的第一个想法(关于位置检查)应该会很好用。任何事件都沿事件发生的 X/Y 方向传递。如果它比窗口的高度/宽度更远,则离开实际窗口。如果它是负面的任何东西,你就离开了窗口。而且,可能,如果它恰好是高度/宽度或恰好是 top: 0 或 left: 0,那么你离开了窗口。

于 2009-11-04T07:46:00.750 回答
0

您的问题来自为窗口内的元素生成的 mouseout 事件,然后按照W3C 事件规范中的描述冒泡。您可以检查实际触发事件的元素:

function mouseoutFunction(event) {
  event = event || window.event;
  var sender = event.srcElement || event.target;
}
于 2009-11-04T07:48:35.933 回答
0

这是我基于计时器的解决方案。这里的计时器基本上是用来给其他事件处理程序(特别是onmouseover)在决定鼠标不在窗口之前执行的机会。1ms 的超时(实际上大约是 33ms,有一个最小的计时器分辨率)给了一点时间让鼠标悬停如果它已经没有发生。

var inWin=0;
window.onmouseout = function(e)
{
   inWin--;
   setTimeout(checkIfOut, 1);
}
window.onmouseover = function(e)
{
   inWin++;
}

function checkIfOut()
{
   if(!inWin)
   {
     //Yay! Mouse is out of the window (probably)
   }
}
于 2009-11-04T09:48:45.490 回答
-1

您可以onmouseout改为在窗口上使用事件

于 2009-11-04T07:19:49.133 回答