如何判断浏览器/选项卡是否处于活动状态

455

可能是重复问题:
有没有办法检测浏览器窗口当前是否处于活动状态?

我有一个函数,每秒钟都会被调用,但我只想在当前页面处于前台时运行它,即用户没有将浏览器最小化或切换到另一个标签页。如果用户没有看着它,那么它就没有任何意义,并且可能会占用大量 CPU 资源,因此我不想在后台浪费周期。

有人知道如何在 JavaScript 中判断这一点吗?

注意:我使用 jQuery,所以如果你的答案使用了它,那就没问题 :)。


28
+1想知道答案。我的关注点不是CPU密集型,而是带宽和服务器密集型。 - mauris
如果您想要一个Jquery插件,请访问https://github.com/keithhackbarth/jquery-window-active。 - keithhackbarth
11
更新:自2013年起,所有主流浏览器都支持所谓的“Visibility API”(可见性API)。点击这里查看一个示例:https://dev59.com/LmIk5IYBdhLWcg3wL7bj#19519701。 - ComFreek
我认为最好的示例在http://daniemon.com/tech/webapps/page-visibility/,戴上耳机播放,你会发现(在你开始视频后)实现非常完美。 - Walter Verhoeven
3
请使用 document.addEventListener("visibilitychange", onchange); 语句,参见 https://dev59.com/d3NA5IYBdhLWcg3wL6sc#1060034 和 https://www.w3.org/TR/page-visibility/。 - Avatar
6个回答

510

除了Richard Simões的答案之外,您还可以使用页面可见性API

if (!document.hidden) {
    // do what you need
}
这个规范定义了一种方法,让站点开发人员可以编程地确定页面的当前可见状态,以便开发功能强大、CPU高效的Web应用程序。
了解更多(2019年更新): - 所有现代浏览器都支持 `document.hidden`,请参考 此处。 - 参考 http://davidwalsh.name/page-visibility。 - 参考 https://developers.google.com/chrome/whitepapers/pagevisibility。 - 示例:当窗口/选项卡被隐藏时暂停视频,请参考 https://web.archive.org/web/20170609212707/http://www.samdutton.com/pageVisibility/

54
赞成这个回答不依赖于jQuery。从长远来看,这似乎也是最好的答案,因为浏览器正在向支持W3C标准的方向发展。David Walsh的示例在Chrome和Firefox上可以工作,但在Safari上不能。 - kronion
6
可见性和聚焦是完全不同的概念。 - Maciej Krawczyk
14
页面可见性 API 检测浏览器是否可见,例如未被最小化或完全覆盖在另一个窗口下。它无法检测到窗口可见但其他窗口是活动状态的情况。 - Juha Syrjälä
4
好的,我会尽力按照您的要求进行翻译。以下是需要翻译的内容:FYI: http://caniuse.com/#search=Page%20Visibility - James Haug
7
@ckknight,你介意将被采纳的答案改为这个吗?这个更新后的答案是我们应该在2019年使用的。 - Matt Westlake
显示剩余8条评论

382

您需要使用窗口的focusblur事件:

var interval_id;
$(window).focus(function() {
    if (!interval_id)
        interval_id = setInterval(hard_work, 1000);
});

$(window).blur(function() {
    clearInterval(interval_id);
    interval_id = 0;
});
回答有关“双击触发”问题的评论,并在jQuery易用性范围内进行操作:
$(window).on("blur focus", function(e) {
    var prevType = $(this).data("prevType");

    if (prevType != e.type) {   //  reduce double fire issues
        switch (e.type) {
            case "blur":
                // do work
                break;
            case "focus":
                // do work
                break;
        }
    }

    $(this).data("prevType", e.type);
})

点击查看示例代码展示(JSFiddle)


9
这个答案并不完美,因为在浏览器中,每当用户执行“聚焦”或“失焦”操作时,focusblur 事件经常会多次触发,此时客户端将会在多个时间间隔上开始执行 hard_work,基本上是同时进行的。 - Jon z
3
我在其他地方读到过,onmousemove 可以作为 focus 的替代方法。 - Michael Robinson
1
@MichaelRobinson 或许是为了最大化/全屏选项卡式浏览器。它可能仍会在Internet Explorer中触发(http://www.bit-tech.net/news/bits/2012/12/13/ie-bug-cursor/1),尽管焦点在其他应用程序上。 - oxygen
1
但是如果用户在页面加载期间切换选项卡,而在调用$(window)focus/blur之前呢?根据您的使用情况,这可能会破坏回调状态和任何后台作业。 (例如,如果您在页面加载时启动后台作业-但是blur从未发生,因为用户在注册$(window).blur之前切换了选项卡?) - KajMagnus
如果用户在页面内点击了一个iframe,这种方法也不起作用。 - red
显示剩余8条评论

178

我会尝试在 window.onfocuswindow.onblur 事件上设置一个标志。

以下代码片段已在 Firefox、Safari 和 Chrome 上进行了测试,请打开控制台并在选项卡之间来回移动:

var isTabActive;

window.onfocus = function () { 
  isTabActive = true; 
}; 

window.onblur = function () { 
  isTabActive = false; 
}; 

// test
setInterval(function () { 
  console.log(window.isTabActive ? 'active' : 'inactive'); 
}, 1000);

在这里尝试一下


1
例子很棒。你有关于IE的想法吗? - mauris
1
我可以确认它在IE7中运行良好,但未测试其他浏览器。这是最佳答案,也是所有功能相同的答案中第一个回答,投票支持它! - Jon z
1
由于某种原因,在 Chrome 上 isActive 总是为 false? - sri
@sri... 不确定是由于一年后的 Chrome 更新,但对于控制台本身,isActive==false,您必须单击主窗口。 - jimm101
8
实际上,Chrome 总是返回 false 的原因是因为 console.log 使用了 window.isActive。删掉 window. 或者在每个地方都加上它。我认为应该将 isActive 初始化为 true 以获得更好的结果。 - Bjørn Stenfeldt
显示剩余7条评论

19

使用jQuery:

$(function() {
    window.isActive = true;
    $(window).focus(function() { this.isActive = true; });
    $(window).blur(function() { this.isActive = false; });
    showIsActive();
});

function showIsActive()
{
    console.log(window.isActive)
    window.setTimeout("showIsActive()", 2000);
}

function doWork()
{
    if (window.isActive) { /* do CPU-intensive stuff */}
}

这是整个回答中最好的答案,本应该得到更高的赞数。 - Yee
因为使用了jQuery而被downvote了,抱歉:),问题中并没有提到jQuery,而且它真的很糟糕。 - Martijn Scheffer

10

除了rockacola的例子,这里所有的示例都要求用户在窗口上物理点击以定义焦点。这不是理想的选择,所以.hover()更好:

$(window).hover(function(event) {
    if (event.fromElement) {
        console.log("inactive");
    } else {
        console.log("active");
    }
});

这将告诉你用户何时在屏幕上移动鼠标,但仍无法告诉你是否在前台而用户的鼠标在其他地方。


2
很好的超越常规思维;然而,如果您试图计算用户停留在页面上的时间,它可能不会很有效。此外,“hover”对于移动浏览器来说不是一个有效的选项。公平地说,我不知道“focus”或“blur”事件绑定是否适用于移动设备。 - Edwin
1
另外,悬停效果取决于鼠标移动。如果使用键盘快捷键输入选项卡,则悬停可能不会触发。 - Kae Verens

9
如果您想要实现类似于在Chrome中打开Google搜索页面时触发某些事件的功能(即当您“聚焦”在页面上时),则可以使用hover()事件来帮助实现。
$(window).hover(function() {
  // code here...
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接