有没有一种方法可以检测浏览器窗口当前是否未激活?


585

我的JavaScript会定期进行活动。当用户不查看站点时(即窗口或选项卡没有焦点),最好不要运行。

有没有办法使用JavaScript做到这一点?

我的参考点:如果您使用的窗口未激活,则Gmail聊天会播放声音。


8
对于那些对以下答案不满意的人,请查看requestAnimationFrameAPI或使用现代功能,即当窗口不可见时(例如,在Chrome中为1秒),降低setTimeout/ 的频率setInterval
罗布W

2
document.body.onblur = function(e){console.log('lama');}适用于非重点元素。
WhyMe 2013年

2
这个答案的一个跨浏览器兼容的解决方案,它使用W3C网页浏览权限API,回落至blur/ focus在浏览器不支持它。
Mathias Bynens

2
以下80%的答案不是此问题的答案。该问题询问当前是否不活跃,但下面的大量答案却不可见,这不是该问题的答案。他们应该被标记为“不是答案”
gman

Answers:


691

自从最初编写此答案以来,由于有了W3C ,新的规范已达到推荐状态。现在,页面可见性API(在MDN上)使我们能够更准确地检测页面何时向用户隐藏。

document.addEventListener("visibilitychange", onchange);

当前的浏览器支持:

  • 铬13+
  • Internet Explorer 10+
  • Firefox 10+
  • Opera 12.10+ [ 阅读笔记 ]

以下代码会退回到不兼容浏览器中不太可靠的模糊/聚焦方法:

(function() {
  var hidden = "hidden";

  // Standards:
  if (hidden in document)
    document.addEventListener("visibilitychange", onchange);
  else if ((hidden = "mozHidden") in document)
    document.addEventListener("mozvisibilitychange", onchange);
  else if ((hidden = "webkitHidden") in document)
    document.addEventListener("webkitvisibilitychange", onchange);
  else if ((hidden = "msHidden") in document)
    document.addEventListener("msvisibilitychange", onchange);
  // IE 9 and lower:
  else if ("onfocusin" in document)
    document.onfocusin = document.onfocusout = onchange;
  // All others:
  else
    window.onpageshow = window.onpagehide
    = window.onfocus = window.onblur = onchange;

  function onchange (evt) {
    var v = "visible", h = "hidden",
        evtMap = {
          focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
        };

    evt = evt || window.event;
    if (evt.type in evtMap)
      document.body.className = evtMap[evt.type];
    else
      document.body.className = this[hidden] ? "hidden" : "visible";
  }

  // set the initial state (but only if browser supports the Page Visibility API)
  if( document[hidden] !== undefined )
    onchange({type: document[hidden] ? "blur" : "focus"});
})();

onfocusinIE 9及更低版本onfocusout必需的,而其他所有语言都使用onfocusonblur(iOS除外,后者使用onpageshow和)onpagehide


1
@bellpeace:IE应当传播focusinfocusout从的IFRAME到上部窗口。对于较新的浏览器,您只需要处理每个iframe 对象上的focusblur事件window。您应该使用我刚刚添加的更新代码,这至少会涵盖较新浏览器中的情况。
Andy E

3
@JulienKronegg:这就是为什么我的答案特别提到页面可见性API的原因,该页面在我最初编写答案后进入工作草案状态。焦点/模糊方法为较旧的浏览器提供了有限的功能。如您所回答的那样,绑定到其他事件并不能涵盖太多,并且更容易出现行为差异(例如,当光标在光标下方弹出窗口时,IE不会触发鼠标退出)。我建议一个更适当的操作是显示一条消息或图标,向用户指示由于页面不活动而导致更新的频率降低。
Andy E

6
@AndyE我在铬上尝试了此解决方案。如果更改选项卡,它将起作用,但是,如果更改窗口(ALT +选项卡),则不会起作用。应该是?这是一个小提琴-jsfiddle.net/8a9N6/17
TonyLâmpada2013年

2
@Heliodor:我想暂时保持答案中的代码最少。从来没有打算将它作为剪切和粘贴的完整解决方案,因为实现者可能希望避免在主体上设置类,而采取完全不同的动作(例如停止和启动计时器)。
Andy E

8
@AndyE您的解决方案似乎仅在用户更改选项卡或最小化/最大化窗口时才有效。但是,如果用户保持选项卡处于活动状态,则不会触发onchange事件,而是使任务栏上的另一个程序最大化。有针对这种情况的解决方案吗?谢谢!
user1491636 2014年

132

我将使用jQuery,因为那么您要做的就是:

$(window).blur(function(){
  //your code here
});
$(window).focus(function(){
  //your code
});

或者至少对我有用。


1
对我来说,这是iframe中的两次通话
桑吉尔,2013年

在Firefox中,如果您在Firebug控制台内(在同一页面上)单击,window将失去焦点,这是正确的,但是取决于您的意图可能不是您的需要。
Majid Fouladpour

21
这不再适用于当前版本的现代浏览器,请参阅批准的答案(页面可见性API)
Jon z

此解决方案在iPad上不起作用,请使用“ pageshow”事件
ElizaS 2014年

页面加载时,BLUR和FOCUS均会触发。当我从页面打开新窗口时,什么都没有发生,但是一旦新窗口关闭,两个事件都将触发:/(使用IE8)
SearchForKnowledge

49

有3种典型方法可用来确定用户是否可以看到HTML页面,但是它们都不完美:

  • W3C网页浏览权限API应该做到这一点(支持,因为:火狐10,MSIE 10,铬13)。但是,仅当完全覆盖浏览器选项卡时(例如,当用户从一个选项卡更改为另一个选项卡时),此API才会引发事件。当无法以100%的精度确定可见性时,API不会引发事件(例如,使用Alt + Tab切换到另一个应用程序)。

  • 使用基于焦点/模糊的方法会给您带来很多误报。例如,如果用户在浏览器窗口上方显示一个较小的窗口,则浏览器窗口将失去焦点(onblur升起),但用户仍然可以看到它(因此仍需要刷新)。另请参见http://javascript.info/tutorial/focus

  • 依靠用户活动(鼠标移动,点击,键键入)也会给您带来很多误报。考虑与上述相同的情况,或者用户正在观看视频。

为了改善上述不完美的行为,我使用了以下3种方法的组合:W3C Visibility API,然后是focus / blur和user activity方法,以减少误报率。这允许管理以下事件:

  • 将浏览器标签更改为另一个标签(100%的准确性,这要归功于W3C Page Visibility API)
  • 页面可能被另一个窗口隐藏,例如由于Alt + Tab(概率=并非100%准确)
  • 用户注意力可能没有集中在HTML页面上(概率=并非100%准确)

它是这样工作的:当文档失去焦点时,将监视文档上的用户活动(例如鼠标移动),以确定该窗口是否可见。页面可见性概率与页面上最后一次用户活动的时间成反比:如果用户长时间未在文档上进行任何活动,则该页面很可能不可见。下面的代码模仿W3C页面可见性API:行为相同,但误报率小。它具有多浏览器的优势(已在Firefox 5,Firefox 10,MSIE 9,MSIE 7,Safari 5,Chrome 9上测试)。

    <div id =“ x”> </ div>

    <脚本>
    / **
    将处理程序注册到给定对象的事件。
    @param obj将引发事件的对象
    @param evType事件类型:单击,按键,鼠标悬停,...
    @param fn事件处理函数
    @param isCapturing设置事件模式(true =捕获事件,false =冒泡事件)
    @return true,如果事件处理程序已正确附加
    * /
    函数addEvent(obj,evType,fn,isCapturing){
      如果(isCapturing == null)isCapturing = false; 
      如果(obj.addEventListener){
        // Firefox
        obj.addEventListener(evType,fn,isCapturing);
        返回true;
      }否则,如果(obj.attachEvent){
        // MSIE
        var r = obj.attachEvent('on'+ evType,fn);
        返回r;
      }其他{
        返回false;
      }
    }

    //注册到潜在的页面可见性更改
    addEvent(document,“ potentialvisilitychange”,function(event){
      document.getElementById(“ x”)。innerHTML + =“ potentialVisilityChange:potentialHidden =” + document.potentialHidden +“,document.potentiallyHiddenSince =” + document.potentiallyHiddenSince +“ s <br>”;
    });

    //注册到W3C页面可见性API
    var hidden = null;
    var visibleChange = null;
    如果(typeof document.mozHidden!==“未定义”){
      hidden =“ mozHidden”;
      ibilityChange =“ mozvisibilitychange”;
    }否则if(typeof document.msHidden!==“ undefined”){
      hidden =“ msHidden”;
      ibilityChange =“ msvisibilitychange”;
    }否则,如果(typeof document.webkitHidden!==“ undefined”){
      hidden =“ webkitHidden”;
      ibilityChange =“ webkitvisibilitychange”;
    } else if(typeof document.hidden!==“ hidden”){
      hidden =“ hidden”;
      ibilityChange =“ visibilitychange”;
    }
    if(hidden!= null && visibleChange!= null){
      addEvent(document,visibleibilityChange,function(event){
        document.getElementById(“ x”)。innerHTML + = visibilityChange +“:” + hidden +“ =” + document [hidden] +“ <br>”;
      });
    }


    var potentialPageVisibility = {
      pageVisibilityChangeThreshold:3 * 3600,//以秒为单位
      init:function(){
        函数setAsNotHidden(){
          var dispatchEventRequired = document.potentialHidden;
          document.potentialHidden = false;
          document.potentiallyHiddenSince = 0;
          如果(dispatchEventRequired)dispatchPageVisibilityChangeEvent();
        }

        函数initPotentiallyHiddenDetection(){
          如果(!hasFocusLocal){
            //窗口没有焦点=>检查窗口中的用户活动
            lastActionDate = new Date();
            如果(timeoutHandler!= null){
              clearTimeout(timeoutHandler);
            }
            timeoutHandler = setTimeout(checkPageVisibility,potentialPageVisibility.pageVisibilityChangeThreshold * 1000 + 100); // +100 ms以避免Firefox下的舍入问题
          }
        }

        函数dispatchPageVisibilityChangeEvent(){
          UnifiedVisilityChangeEventDispatchAllowed = false;
          var evt = document.createEvent(“ Event”);
          evt.initEvent(“ potentialvisilitychange”,true,true);
          document.dispatchEvent(evt);
        }

        函数checkPageVisibility(){
          var potentialHiddenDuration =(hasFocusLocal || lastActionDate == null?0:Math.floor((new Date()。getTime()-lastActionDate.getTime())/ 1000));;
                                        document.potentiallyHiddenSince = potentialHiddenDuration;
          如果(potentialHiddenDuration> = potentialPageVisibility.pageVisibilityChangeThreshold &&!document.potentialHidden){
            //提升网页的可见度更改阈值=>提高均匀度
            document.potentialHidden = true;
            dispatchPageVisibilityChangeEvent();
          }
        }

        var lastActionDate = null;
        var hasFocusLocal = true;
        var hasMouseOver = true;
        document.potentialHidden = false;
        document.potentiallyHiddenSince = 0;
        var timeoutHandler = null;

        addEvent(document,“ pageshow”,function(event){
          document.getElementById(“ x”)。innerHTML + =“ pageshow / doc:<br>”;
        });
        addEvent(document,“ pagehide”,function(event){
          document.getElementById(“ x”)。innerHTML + =“ pagehide / doc:<br>”;
        });
        addEvent(window,“ pageshow”,function(event){
          document.getElementById(“ x”)。innerHTML + =“ pageshow / win:<br>”; //页面首次显示时引发
        });
        addEvent(window,“ pagehide”,function(event){
          document.getElementById(“ x”)。innerHTML + =“ pagehide / win:<br>”; //没有提出
        });
        addEvent(document,“ mousemove”,function(event){
          lastActionDate = new Date();
        });
        addEvent(document,“ mouseover”,function(event){
          hasMouseOver = true;
          setAsNotHidden();
        });
        addEvent(document,“ mouseout”,function(event){
          hasMouseOver = false;
          initPotentiallyHiddenDetection();
        });
        addEvent(window,“ blur”,function(event){
          hasFocusLocal = false;
          initPotentiallyHiddenDetection();
        });
        addEvent(window,“ focus”,function(event){
          hasFocusLocal = true;
          setAsNotHidden();
        });
        setAsNotHidden();
      }
    }

    potentialPageVisibility.pageVisibilityChangeThreshold = 4; // 4秒进行测试
    potentialPageVisibility.init();
    </ script>

由于当前没有没有误报的跨浏览器解决方案,因此您最好对禁用网站上的定期活动进行三思。


在字符串“ undefined”而不是undefined关键字上使用严格的比较运算符会不会导致上述代码中的误报?
乔纳森(Jonathon)

@kiran:实际上它与Alt + Tab一起使用。当您执行Alt + Tab键时,无法确定页面是否被隐藏,因为您可能会切换到一个较小的窗口,因此不能保证页面被完全隐藏。这就是为什么我使用“可能隐藏”的概念的原因(在示例中,阈值设置为4秒,因此您至少需要使用Alt + Tab切换到另一个窗口至少4秒)。但是,您的评论表明答案不是很清楚,所以我改了字。
朱利安·克朗格

@JulienKronegg我认为这是最好的解决方案。但是,以上代码非常需要一些重构和抽象。您为什么不将其上传到GitHub并让社区对其进行重构?
雅各布

1
@Jacob很高兴您喜欢我的解决方案。随意将其自己推广到GitHub项目。我给代码提供了Creative Commons许可,作者:creativecommons.org/licenses/by/4.0
Julien Kronegg '17

26

GitHub上有一个整洁的库:

https://github.com/serkanyersen/ifvisible.js

例:

// If page is visible right now
if( ifvisible.now() ){
  // Display pop-up
  openPopUp();
}

我已经在所有浏览器上测试了1.0.1版,并且可以确认该版本适用于:

  • IE9,IE10
  • FF 26.0
  • 镀铬34.0

...以及可能所有较新的版本。

不能与以下产品完全配合使用:

  • IE8-始终指示选项卡/窗口当前处于活动状态(.now()始终true为我返回)

接受的答案在IE9中引起了问题。这个图书馆很棒。
汤姆·特曼

20

使用: 页面可见性API

document.addEventListener( 'visibilitychange' , function() {
    if (document.hidden) {
        console.log('bye');
    } else {
        console.log('well back');
    }
}, false );

我可以用吗 ? http://caniuse.com/#feat=pagevisibility


问题不在于页面可见性。大约不活跃/活跃
gman

我认为OP并不是在谈论ide的功能
l2aelba '18

1
我也不是在谈论ide。我说的是alt-tabbing / cmd-tab另一个应用程序。突然页面未激活。页面可见性api不能帮助我知道页面是否处于活动状态,它只能帮助我知道页面是否可能不可见。
gman

18

我为我的应用创建了彗星聊天,当我收到其他用户的消息时,我使用:

if(new_message){
    if(!document.hasFocus()){
        audio.play();
        document.title="Have new messages";
    }
    else{
        audio.stop();
        document.title="Application Name";
    } 
}

2
支持IE6的最干净解决方案
Paul Cooper

4
document.hasFocus()是最干净的方法。使用基于可见性api或事件或查找各种级别的用户活动/缺乏活动的所有其他方式变得过于复杂,并且充满了边缘情况和漏洞。将其放在一个简单的时间间隔上,并在结果更改时引发自定义事件。示例:jsfiddle.net/59utucz6/1
danatcofo

1
高效且与其他解决方案不同的是,当您切换到另一个浏览器选项卡或窗口,甚至切换到另一个应用程序时,都能提供正确的反馈。
ow3n

毫无疑问,这是最干净的方法,但是在Firefox中不起作用
hardik chugh

1
如果我打开Chrome Dev工具,则document.hasFocus()等于false。或者即使您单击浏览器的顶部面板,也会发生同样的情况。我不确定该解决方案是否适合暂停视频,动画等
tylik

15

我开始使用社区Wiki答案,但意识到它没有在Chrome中检测到alt-tab事件。这是因为它使用了第一个可用的事件源,在这种情况下,它是页面可见性API,在Chrome中似乎不跟踪alt标签。

我决定稍微修改一下脚本,以跟踪页面焦点更改的所有可能事件。您可以使用以下功能:

function onVisibilityChange(callback) {
    var visible = true;

    if (!callback) {
        throw new Error('no callback given');
    }

    function focused() {
        if (!visible) {
            callback(visible = true);
        }
    }

    function unfocused() {
        if (visible) {
            callback(visible = false);
        }
    }

    // Standards:
    if ('hidden' in document) {
        document.addEventListener('visibilitychange',
            function() {(document.hidden ? unfocused : focused)()});
    }
    if ('mozHidden' in document) {
        document.addEventListener('mozvisibilitychange',
            function() {(document.mozHidden ? unfocused : focused)()});
    }
    if ('webkitHidden' in document) {
        document.addEventListener('webkitvisibilitychange',
            function() {(document.webkitHidden ? unfocused : focused)()});
    }
    if ('msHidden' in document) {
        document.addEventListener('msvisibilitychange',
            function() {(document.msHidden ? unfocused : focused)()});
    }
    // IE 9 and lower:
    if ('onfocusin' in document) {
        document.onfocusin = focused;
        document.onfocusout = unfocused;
    }
    // All others:
    window.onpageshow = window.onfocus = focused;
    window.onpagehide = window.onblur = unfocused;
};

像这样使用它:

onVisibilityChange(function(visible) {
    console.log('the page is now', visible ? 'focused' : 'unfocused');
});

此版本侦听所有不同的可见性事件,并在其中任何一个引起更改的情况下触发回调。在focusedunfocused处理器确保回调不叫多次,如果多个API搭上同一可见性改变。


例如,Chrome浏览器同时具有document.hiddendocument.webkitHidden。没有elseif构造中,我们将得到2个回调调用吗?
克里斯蒂安·韦斯特贝克

@ChristiaanWesterbeek很好,我没想到!如果您可以编辑此帖子,请继续,我会接受:)
Daniel Buckmaster

嘿,等等:编辑由ChristiaanWesterbeek建议并实际上由@ 1.21Gigawatts添加的“ else”似乎不是一个好主意:它击败了Daniel最初购买的想法,即尝试所有支持的方法。并行方法。而且没有回调被调用两次的风险,因为focused()和unfocused()会在没有任何变化的情况下抑制额外的调用。确实好像我们应该恢复到第一转。
Louis Semprini

@LouisSemprini很棒。我忘记了代码的初衷!我已经恢复了原件并添加了解释!
丹尼尔·巴克马斯特

从今天开始检查,至少在Chrome 78 + macOS上它无法检测到alt + tab
Hugo Gresse

7

这确实很棘手。鉴于以下要求,似乎没有解决方案。

  • 该页面包含您无法控制的iframe
  • 无论跟踪是由TAB更改(ctrl + tab)还是由窗口更改(alt + tab)触发的,您都希望跟踪可见性状态更改

发生这种情况是因为:

  • 页面Visibility API可以可靠地告诉您选项卡的更改(即使使用iframe),但不能告诉您用户何时更改窗口。
  • 只要iframe没有焦点,聆听窗口模糊/焦点事件就可以检测alt + tab和ctrl + tab。

鉴于这些限制,有可能实现一个解决方案,该解决方案将以下各项结合在一起:-页面可见性API-窗口模糊/焦点-document.activeElement

能够:

  • 1)父页面具有焦点时按Ctrl + Tab:是
  • 2)当iframe具有焦点时,按ctrl + tab:是
  • 3)当父页面具有焦点时,按alt + tab:是
  • 4)当iframe具有焦点时,按alt + tab: <-讨厌

当iframe具有焦点时,根本不会调用您的模糊/焦点事件,并且页面可见性API不会在alt + tab上触发。

我以@AndyE的解决方案为基础,并在这里实现了这个(几乎是很好的)解决方案:https : //dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test1.html(对不起,我在JSFiddle上遇到了一些麻烦)。

这也可以在Github上获得:https : //github.com/qmagico/estante-components

这适用于铬/铬。除了不加载iframe内容(知道为什么吗?)之外,它在firefox上有效

无论如何,要解决最后一个问题(4),唯一的方法是在iframe上监听模糊/聚焦事件。如果您对iframe有所控制,则可以使用postMessage API来执行此操作。

https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test2.html

我仍然没有在足够多的浏览器上对此进行测试。如果您可以找到有关此功能无效的更多信息,请在下面的评论中告诉我。


在我的测试中,它还适用于IE9,IE10和Android上的Chrome。
TonyLâmpada2013年

1
这似乎IPAD需要一个完全不同的解决方案- stackoverflow.com/questions/4940657/...
托尼Lâmpada

3
所有这些链接都是404s :(
丹尼尔·巴克马斯特

6
var visibilityChange = (function (window) {
    var inView = false;
    return function (fn) {
        window.onfocus = window.onblur = window.onpageshow = window.onpagehide = function (e) {
            if ({focus:1, pageshow:1}[e.type]) {
                if (inView) return;
                fn("visible");
                inView = true;
            } else if (inView) {
                fn("hidden");
                inView = false;
            }
        };
    };
}(this));

visibilityChange(function (state) {
    console.log(state);
});

http://jsfiddle.net/ARTsinn/JTxQY/


5

这对我适用于chrome 67,firefox 67,

if(!document.hasFocus()) {
    // do stuff
}

3

您可以使用:

(function () {

    var requiredResolution = 10; // ms
    var checkInterval = 1000; // ms
    var tolerance = 20; // percent


    var counter = 0;
    var expected = checkInterval / requiredResolution;
    //console.log('expected:', expected);

    window.setInterval(function () {
        counter++;
    }, requiredResolution);

    window.setInterval(function () {
        var deviation = 100 * Math.abs(1 - counter / expected);
        // console.log('is:', counter, '(off by', deviation , '%)');
        if (deviation > tolerance) {
            console.warn('Timer resolution not sufficient!');
        }
        counter = 0;
    }, checkInterval);

})();


2

这是对Andy E的回答的改编。

这将执行一项任务,例如每30秒刷新一次页面,但前提是该页面可见且集中。

如果无法检测到可见性,则仅使用焦点。

如果用户将页面聚焦,那么它将立即更新

直到任何ajax调用后30秒,页面才会再次更新

var windowFocused = true;
var timeOut2 = null;

$(function(){
  $.ajaxSetup ({
    cache: false
  });
  $("#content").ajaxComplete(function(event,request, settings){
       set_refresh_page(); // ajax call has just been made, so page doesn't need updating again for 30 seconds
   });
  // check visibility and focus of window, so as not to keep updating unnecessarily
  (function() {
      var hidden, change, vis = {
              hidden: "visibilitychange",
              mozHidden: "mozvisibilitychange",
              webkitHidden: "webkitvisibilitychange",
              msHidden: "msvisibilitychange",
              oHidden: "ovisibilitychange" /* not currently supported */
          };
      for (hidden in vis) {
          if (vis.hasOwnProperty(hidden) && hidden in document) {
              change = vis[hidden];
              break;
          }
      }
      document.body.className="visible";
      if (change){     // this will check the tab visibility instead of window focus
          document.addEventListener(change, onchange,false);
      }

      if(navigator.appName == "Microsoft Internet Explorer")
         window.onfocus = document.onfocusin = document.onfocusout = onchangeFocus
      else
         window.onfocus = window.onblur = onchangeFocus;

      function onchangeFocus(evt){
        evt = evt || window.event;
        if (evt.type == "focus" || evt.type == "focusin"){
          windowFocused=true; 
        }
        else if (evt.type == "blur" || evt.type == "focusout"){
          windowFocused=false;
        }
        if (evt.type == "focus"){
          update_page();  // only update using window.onfocus, because document.onfocusin can trigger on every click
        }

      }

      function onchange () {
        document.body.className = this[hidden] ? "hidden" : "visible";
        update_page();
      }

      function update_page(){
        if(windowFocused&&(document.body.className=="visible")){
          set_refresh_page(1000);
        }
      }


  })();
  set_refresh_page();
})

function get_date_time_string(){
  var d = new Date();
  var dT = [];
  dT.push(d.getDate());
  dT.push(d.getMonth())
  dT.push(d.getFullYear());
  dT.push(d.getHours());
  dT.push(d.getMinutes());
  dT.push(d.getSeconds());
  dT.push(d.getMilliseconds());
  return dT.join('_');
}

function do_refresh_page(){

// do tasks here

// e.g. some ajax call to update part of the page.

// (date time parameter will probably force the server not to cache)

//      $.ajax({
//        type: "POST",
//        url: "someUrl.php",
//        data: "t=" + get_date_time_string()+"&task=update",
//        success: function(html){
//          $('#content').html(html);
//        }
//      });

}

function set_refresh_page(interval){
  interval = typeof interval !== 'undefined' ? interval : 30000; // default time = 30 seconds
  if(timeOut2 != null) clearTimeout(timeOut2);
  timeOut2 = setTimeout(function(){
    if((document.body.className=="visible")&&windowFocused){
      do_refresh_page();
    }
    set_refresh_page();
  }, interval);
}

依靠焦点/模糊方法不起作用(它给您带来很多误报),请参见stackoverflow.com/a/9502074/698168
Julien Kronegg 2012年

2

对于没有jQuery的解决方案,请查看Visibility.js,其中提供了有关三个页面状态的信息

visible    ... page is visible
hidden     ... page is not visible
prerender  ... page is being prerendered by the browser

以及setInterval的便捷包装

/* Perform action every second if visible */
Visibility.every(1000, function () {
    action();
});

/* Perform action every second if visible, every 60 sec if not visible */
Visibility.every(1000, 60*1000, function () {
    action();
});

还提供旧版浏览器(IE <10; iOS <7)的后备版本


浏览器支持如何?目前,您可以使用Chrome,Safari和Firefox进行分叉。
Selva Ganapathi

1

稍微复杂一点的方法是用来setInterval()检查鼠标位置并与上一次检查进行比较。如果鼠标没有在设定的时间内移动,则用户可能处于空闲状态。

这具有告诉用户是否空闲的附加优点,而不仅仅是检查窗口是否处于活动状态。

正如许多人指出的那样,这并不总是一种检查用户或浏览器窗口是否空闲的好方法,因为用户甚至可能没有使用鼠标或正在观看视频等。我只是建议一种检查空闲状态的可能方法。


30
除非用户没有鼠标。
user1686 2009年


如果用户正在观看视频,这也不会播放骰子
jamiew 2011年

您可以使用onkeypress或其他类似事件重置计时器并解决非鼠标问题。当然,它仍然会为用户没有工作积极寻找页面观看视频,学习图像等
joshuahedlund

1

对于angular.js,这是一条指令(基于接受的答案),该指令将使您的控制器对可见性的变化做出反应:

myApp.directive('reactOnWindowFocus', function($parse) {
    return {
        restrict: "A",
        link: function(scope, element, attrs) {
            var hidden = "hidden";
            var currentlyVisible = true;
            var functionOrExpression = $parse(attrs.reactOnWindowFocus);

          // Standards:
          if (hidden in document)
            document.addEventListener("visibilitychange", onchange);
          else if ((hidden = "mozHidden") in document)
            document.addEventListener("mozvisibilitychange", onchange);
          else if ((hidden = "webkitHidden") in document)
            document.addEventListener("webkitvisibilitychange", onchange);
          else if ((hidden = "msHidden") in document)
            document.addEventListener("msvisibilitychange", onchange);
          else if ("onfocusin" in document) {
                // IE 9 and lower:
            document.onfocusin = onshow;
                document.onfocusout = onhide;
          } else {
                // All others:
            window.onpageshow = window.onfocus = onshow;
                window.onpagehide = window.onblur = onhide;
            }

          function onchange (evt) {
                //occurs both on leaving and on returning
                currentlyVisible = !currentlyVisible;
                doSomethingIfAppropriate();
          }

            function onshow(evt) {
                //for older browsers
                currentlyVisible = true;
                doSomethingIfAppropriate();
            }

            function onhide(evt) {
                //for older browsers
                currentlyVisible = false;
                doSomethingIfAppropriate();
            }

            function doSomethingIfAppropriate() {
                if (currentlyVisible) {
                    //trigger angular digest cycle in this scope
                    scope.$apply(function() {
                        functionOrExpression(scope);
                    });
                }
            }
        }
    };

});

您可以像以下示例一样使用它:<div react-on-window-focus="refresh()">refresh()无论哪个Controller在范围内,范围函数在哪里。


0

这是一个可靠的现代解决方案。(甜蜜Sh)

document.addEventListener("visibilitychange", () => {
  console.log( document.hasFocus() )
})

这将设置一个侦听器,以在激发可见性事件(可能是焦点或模糊)时触发。


0

如果您想整个浏览器进行模糊处理:如我所评论,如果浏览器失去焦点,则不会触发任何建议的事件。我的想法是循环计数并在发生事件时重置计数器。如果计数器达到极限,我可以在location.href到另一页。如果您使用开发工具,这也会触发。

var iput=document.getElementById("hiddenInput");
   ,count=1
   ;
function check(){
         count++;
         if(count%2===0){
           iput.focus();
         }
         else{
           iput.blur();
         }
         iput.value=count;  
         if(count>3){
           location.href="http://Nirwana.com";
         }              
         setTimeout(function(){check()},1000);
}   
iput.onblur=function(){count=1}
iput.onfocus=function(){count=1}
check();

这是在FF上成功测试的草案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.