检测浏览器选项卡是否具有焦点

Fen*_*ton 131 javascript optimization polling

是否有可靠的跨浏览器方式来检测选项卡是否具有焦点.

场景是我们有一个应用程序定期轮询股票价格,如果页面没有焦点我们可以停止轮询并节省每个人的交通噪音,特别是当人们是打开不同组合的几个选项卡的粉丝.

window.onblurwindow.onfocus这个选项?

Rya*_*ght 112

是的,window.onfocus并且window.onblur应该为您的方案的工作:

http://www.thefutureoftheweb.com/blog/detect-browser-window-focus

  • 请注意,您无法通过这种方式区分页面加载时处于活动状态或非活动状态的页面. (7认同)
  • onfocusin/onfocusout方面,以及关于告诉用户你已暂停的说明都是非常好的笔记.谢谢. (3认同)
  • @vsync - 阅读链接的文章,您会看到它同时使用了“onfocusin”和“onfocus”。 (2认同)

Zir*_*rak 49

重要编辑:这个答案已经过时了.自编写以来,已经引入了Visibility API( mdn, example, spec).这是解决这个问题的更好方法.


var focused = true;

window.onfocus = function() {
    focused = true;
};
window.onblur = function() {
    focused = false;
};
Run Code Online (Sandbox Code Playgroud)

据我所知,focus并且blur都支持...一切.(见http://www.quirksmode.org/dom/events/index.html)

  • 只需注意一点,使用所有这些解决方案,您就会冒着用户在javascript完全加载之前更改标签的风险,从而将错误的值分配给焦点.不确定它是否有好的方法. (2认同)
  • 这是一个危险的解决方案,因为它存在覆盖大型应用程序中某些其他事件侦听器的风险。您应该遵循这个答案:/sf/answers/1535452201/ (2认同)

Ili*_*ija 44

在搜索此问题时,我发现建议应使用Page Visibility API.大多数现代浏览器都支持此API,我可以使用:http://caniuse.com/#feat=pagevisibility.

这是一个工作示例(源自此代码段):

$(document).ready(function() {
  var hidden, visibilityState, visibilityChange;

  if (typeof document.hidden !== "undefined") {
    hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState";
  } else if (typeof document.msHidden !== "undefined") {
    hidden = "msHidden", visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState";
  }

  var document_hidden = document[hidden];

  document.addEventListener(visibilityChange, function() {
    if(document_hidden != document[hidden]) {
      if(document[hidden]) {
        // Document hidden
      } else {
        // Document shown
      }

      document_hidden = document[hidden];
    }
  });
});
Run Code Online (Sandbox Code Playgroud)

更新:上面的示例曾经为Gecko和WebKit浏览器提供了前缀属性,但我删除了该实现,因为这些浏览器现在提供的页面可见性API没有前缀.我保留了Microsoft特定的前缀,以便与IE10保持兼容.


Bri*_*laz 29

是的,那些应该适合你.您刚刚提醒我,我遇到的这个链接利用了这些技术.有趣的阅​​读

  • +1 - 这是一个非常聪明的伎俩,我可以想象愚弄了很多人. (2认同)
  • 多么巧妙和狡猾的攻击.有趣的读到,谢谢. (2认同)

Sho*_*ikh 27

发布这个答案是因为我在接受的答案中发现了一个错误。

该错误是当您在聚焦窗口上打开开发人员控制台并单击其上的任意位置时,开发人员控制台现在具有焦点,此时window.onfocuswindow.onblur没有任何效果。

所以这是我的解决方案,

document.addEventListener("visibilitychange", function() {
    if (document.visibilityState === 'visible') {
        console.log('has focus');
    } else {
        console.log('lost focus');
    }
});
Run Code Online (Sandbox Code Playgroud)

了解更多https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event


ale*_*son 24

很惊讶没有人提到 document.hasFocus

if (document.hasFocus()) console.log('Tab is active')
Run Code Online (Sandbox Code Playgroud)

MDN有更多信息.

  • 正确答案再次出现在最底部。去 StackOverflow 的方式! (4认同)
  • 唯一的缺点是,如果您尝试确定选项卡是否在 iframe 内获得焦点,那么如果在父页面仍处于焦点之外时加载 iframe,则会失败。为了涵盖这一点,您必须使用页面可见性 api。 (2认同)
  • 如果您仅单击选项卡标题,则 document.hasFocus() 值不会更改,因为它位于文档上,您必须单击文档才能看到更改。这是一个缺点。 (2认同)

con*_*ile 7

我会这样做(参考http://www.w3.org/TR/page-visibility/):

    window.onload = function() {

        // check the visiblility of the page
        var hidden, visibilityState, visibilityChange;

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


        if (typeof document.addEventListener === "undefined" || typeof hidden === "undefined") {
            // not supported
        }
        else {
            document.addEventListener(visibilityChange, function() {
                console.log("hidden: " + document[hidden]);
                console.log(document[visibilityState]);

                switch (document[visibilityState]) {
                case "visible":
                    // visible
                    break;
                case "hidden":
                    // hidden
                    break;
                }
            }, false);
        }

        if (document[visibilityState] === "visible") {
            // visible
        }

    };  
Run Code Online (Sandbox Code Playgroud)