检测浏览器标签是否处于活跃状态或用户切换了标签页

65

如何检测用户是否切换到另一个浏览器选项卡?

目前,我有以下代码:

$(window).on("blur focus", function (e) {

    var prevType = $(this).data("prevType");

    if (prevType != e.type) { //  reduce double fire issues
        switch (e.type) {
            case "blur":
                $('.message').html('<div class="alert alert-error">Oops. You navigated away from the ads <a id="start" class="butt green">Resume</a></div>');

                var myDiv = $("#bar");
                myDiv.clearQueue();
                myDiv.stop();
                clearInterval($timer);
                $timer = null;
                break;
            case "focus":
                // do work
                break;
        }
    }

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

但这仅适用于用户最小化活动窗口时。


2
在我看来,那些问答已经过时了。现在的可见性 API 可以提供更好的答案。 - Denys Séguret
1
我同意dystroy的观点。这两个都已经超过四年了;网络自那时以来发生了很大变化。然而,oliverbj,你最好将它们作为参考,供那些使用旧浏览器的人使用。 - Matt Grande
@MattGrande 也许应该在那里发布更新后的答案,是吧? - John Dvorak
@JanDvorak 我在两个问题下都写了评论。 - ComFreek
5个回答

175
现在我们可以使用可见性API
为了处理不同的浏览器特定语法,我写了这个小代码:
var vis = (function(){
    var stateKey, eventKey, keys = {
        hidden: "visibilitychange",
        webkitHidden: "webkitvisibilitychange",
        mozHidden: "mozvisibilitychange",
        msHidden: "msvisibilitychange"
    };
    for (stateKey in keys) {
        if (stateKey in document) {
            eventKey = keys[stateKey];
            break;
        }
    }
    return function(c) {
        if (c) document.addEventListener(eventKey, c);
        return !document[stateKey];
    }
})();

使用:

var visible = vis(); // gives current state

vis(aFunction);      // registers a handler for visibility changes

示例:

vis(function(){
  document.title = vis() ? 'Visible' : 'Not visible';
});

演示页面


1
谢谢您,但我无法将您的代码放入AngularJS中。它不起作用。 - John Nguyen
3
@Ali.NET 我在所有浏览器上都使用它。 - Denys Séguret
在Firefox 41(Linux)中,它不能按预期工作。如果我切换浏览器选项卡,它可以正常工作。如果我最小化浏览器窗口,它也可以正常工作。但是,如果我切换到另一个应用程序,则无法正常工作。即使另一个窗口处于活动状态,“document.hidden”属性仍保持为“false”。 - pumbo
1
@pumbo 是的,目前可见性API并不总是能够知道另一个应用程序是否隐藏了浏览器。我认为目前没有获取该信息的方法。 - Denys Séguret
2
@waterkinq,没有可靠的方法可以在标签页/浏览器关闭时采取行动。这是一种设计选择(5年前情况不同)。这意味着您绝不能依赖于浏览器通知您断开连接,而必须在服务器端正确处理它。 - Denys Séguret
显示剩余10条评论

29

另请参见https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event,该文档建议同时检查“pagehide”。 - Marcus
2
现在推荐使用 document.visibilityState 代替 document.hidden - Greg
如何在Angular中更新本地变量?假设我有一个本地变量userOnPage,我想将其设置为true或false。当我执行this.userOnPage = document.hiden时,我会收到以下错误:属性'userOnPage'在类型文档上不存在。 - alpha027

9
如果您想检测选项卡对用户是否可见,请使用 document.visibilityState 进行检查(只读属性)。虽然 document.hidden 也可以,如其他人所写,但是W3C认为它“历史悠久”,并建议使用前者。
如果您只想知道选项卡是否处于活动状态,请使用 document.hasFocus() 进行检查。在这种情况下,选项卡仍然可以可见但不活动(例如有两个平行浏览器窗口,其中只有一个是活动的,两个窗口都可见)。
如果您想捕获可视性状态(自然地也包括活动状态),则可以从Page Visibility API监听 visibilitychange 事件。

同时使用以上三种方法的示例:

// Capture change to visibility
document.addEventListener("visibilitychange", function() {
    // Check if tab content is visible
    if (document.visibilityState) { 
        console.log("Tab is visible!") 
    }

    // Check if tab is active
    if (document.hasFocus()) {
        console.log("Tab is active!");
    }
});

处理浏览器兼容性

您可以设置以下检查方式以覆盖不兼容的浏览器。

注意:由于它在IE6上始终兼容,因此不包括hasFocus()

var visibilityState, visibilityChange;
if (typeof document.visibilityState !== "undefined") {
    visibilityState = "visibilityState";
    visibilityChange = "visibilitychange";
} 
else if (typeof document.mozVisibilityState !== "undefined") {
    visibilityState = "mozVisibilityState";
    visibilityChange = "mozvisibilitychange";
} 
else if (typeof document.msVisibilityState !== "undefined") {
    visibilityState = "msVisibilityState";
    visibilityChange = "msvisibilitychange";
} 
else if (typeof document.webkitVisibilityState !== "undefined") {
    visibilityState = "webkitVisibilityState";
    visibilityChange = "webkitvisibilitychange";
}

if (visibilityChange != null && visibilityState != null) {
    document.addEventListener(visibilityChange, function() {
        if (document[visibilityState]) { 
            console.log("Tab is visible!") 
        }
    }, false);
}

MDN快速参考


7

案例 1

只需在您的构造函数中添加此EventListener

document.addEventListener("visibilitychange", function() {
      if (document.hidden) {
        //do whatever you want
        console.log("Hidden");
      }
      else {
        //do whatever you want
        console.log("SHOWN");
      }
});

情况 2

如果您更改选项卡,$(window).blur(function () 函数将被调用,如果您再次返回此选项卡,则会调用 $(window).focus(function () 函数。 在您的构造函数中添加此代码

$(window).focus(function () {
      //do something
       console.log("You are in this tab");
});

$(window).blur(function () {
      //do something
       console.log("You left this tab");
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Click here and click outside of this..</p>


4

这是一个ES6多浏览器解决方案,我用它来确定选项卡的可见性。我从Deny的解决方案中获得了灵感,并根据我的需求进行了调整。

const vis = (c) => {
  let self = this
  const browserProps = {
    hidden: "visibilitychange",
    msHidden: "msvisibilitychange",
    webkitHidden: "webkitvisibilitychange",
    mozHidden: "mozvisibilitychange",
  }
  for (item in browserProps) {
    if (item in document) {
      eventKey = browserProps[item]
      break
    }
  }

  if (c) {
    if (!self._init && !(typeof document.addEventListener === "undefined")) {
      document.addEventListener(eventKey, c)
      self._init = true
      c()
    } 
  }
  return  !document[item] 
}

vis(() => {
  let tabVisibility = vis() ? 'Visible' : 'Not visible';
  console.log(tabVisibility)
})


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