这个问题在这里已经有答案了:

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

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

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

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

我有一些想法:

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

我们使用prototype.js,所以理想情况下我想用prototype的Event.observe来表达解决方案,但我可以弄清楚那部分。

感谢您的任何建议!

有帮助吗?

解决方案

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

细节:

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

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

将鼠标悬停在鼠标上时,relatedTarget 属性引用 指针来了。在鼠标输出时, relatedTarget 属性引用 指针所到的节点。上 任何事件,范围是 事件所附加的。当 relatedTarget 不是 currentTarget,鼠标悬停事件为 等效于 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) 可能包含此功能,但我找不到任何明确的内容。

其他提示

仅使用 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. 。如果是 true, mouseover 也不会触发。

也许您可以为鼠标悬停和鼠标移出设置监听器 document, body 或包装整个文档的其他元素,并使用它(通过保存它发生的情况)作为触发器来确定它是否是窗口上的有效鼠标悬停?

如果做不到这一点,你的第一个想法(关于位置检查)应该效果很好。任何事件都会沿着事件发生的 X/Y 方向传递。如果它比窗口的高度/宽度更远,则您离开了实际的窗口。如果有任何负面影响,你就离开了窗户。并且,可能,如果它恰好是高度/宽度或恰好是顶部:0 或左:0,然后你离开了窗户。

当鼠标离开任何元素(包括窗口)时,窗口对象将触发 mouseout 事件并通过 event 对象随之而来。

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

通过测试该项目是否 null 在一个 mouseout 事件,你可以判断鼠标是否离开了窗口。这是代码:

window.onmouseout=function(event){ 
  if(event.toElement===null) console.log('the mouse left the window'); 
}

您的问题来自于为元素生成的 mouseout 事件 里面 窗口,然后按照中所述冒泡 W3C 事件规范. 。您可以检查事件实际上是在哪个元素上触发的:

function mouseoutFunction(event) {
  event = event || window.event;
  var sender = event.srcElement || event.target;
}

这是我基于计时器的解决方案。这里的计时器基本上用于在确定 mosue 超出窗口之前为其他事件处理程序(特别是 onmouseover)提供执行的机会。1 毫秒的超时(实际上大约 33 毫秒,有一个最小计时器分辨率)为鼠标悬停(如果鼠标悬停尚未发生)提供了一点时间。

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)
   }
}

您可以使用 onmouseout 窗口上的事件

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top