Javascript 是否有方法检测浏览器窗口当前是否未处于活动状态?

Javascript 是否有方法检测浏览器窗口当前是否未处于活动状态?,javascript,browser,focus,window,Javascript,Browser,Focus,Window,我有JavaScript,它定期进行活动。当用户没有查看站点时(即窗口或选项卡没有焦点),最好不要运行 有没有一种方法可以使用JavaScript实现这一点 我的参考点是:如果你使用的窗口不活动,Gmail聊天会播放声音 自从最初编写这个答案以来,多亏了W3C,一个新的规范已经达到了推荐状态。 (on)现在允许我们更准确地检测用户何时隐藏页面 document.addEventListener("visibilitychange", onchange); 当前浏览器支持: 铬13+ Inte

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

有没有一种方法可以使用JavaScript实现这一点


我的参考点是:如果你使用的窗口不活动,Gmail聊天会播放声音

自从最初编写这个答案以来,多亏了W3C,一个新的规范已经达到了推荐状态。 (on)现在允许我们更准确地检测用户何时隐藏页面

document.addEventListener("visibilitychange", onchange);
当前浏览器支持:

  • 铬13+
  • Internet Explorer 10+
  • 火狐10+
  • 歌剧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"});
})();

onfocusin
onfocusout
是,而除iOS外,其他所有的都使用
onfocus
onblur
,iOS使用
onpageshow
onpagehide

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

这样做的另一个好处是可以告诉用户是否空闲,而不仅仅是检查窗口是否处于活动状态


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

在HTML 5中,您还可以使用:

  • onpageshow
    :窗口可见时要运行的脚本
  • onpagehide
    :隐藏窗口时要运行的脚本
见:


我会使用jQuery,因为这样您所要做的就是:

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

或者至少它对我有效。

有3种典型的方法用于确定用户是否可以看到HTML页面,但是没有一种方法可以完美地工作:

  • 应该这样做(从Firefox 10、MSIE 10、Chrome 13开始支持)。但是,此API仅在完全覆盖浏览器选项卡时(例如,当用户从一个选项卡更改为另一个选项卡时)才会引发事件。当无法100%准确地确定可见性时(例如,Alt+Tab切换到其他应用程序),API不会引发事件

  • 使用基于聚焦/模糊的方法会产生大量假阳性。例如,如果用户在浏览器窗口顶部显示一个较小的窗口,浏览器窗口将失去焦点(
    onblur
    risted),但用户仍能看到它(因此仍需要刷新)。另见

  • 依赖用户活动(鼠标移动、单击、键入键)也会给您带来很多误报。考虑与上面相同的情况,或者用户正在观看视频
为了改善上述不完美行为,我结合使用了3种方法:W3C Visibility API、focus/blur和user activity方法,以降低误报率。这允许管理以下事件:

  • 将浏览器选项卡更改为另一个选项卡(由于W3C页面可见性API,精确度达到100%)
  • 页面可能被另一个窗口隐藏,例如由于Alt+Tab(概率=不100%准确)
  • 用户注意力可能不集中在HTML页面上(概率=不100%准确)
这就是它的工作原理:当文档失去焦点时,会监视文档上的用户活动(如鼠标移动),以确定窗口是否可见。页面可见性概率与页面上最后一个用户活动的时间成反比:如果用户长时间不在文档上活动,则页面很可能不可见。下面的代码模拟了W3C页面可见性API:其行为方式相同,但误报率很低。它具有多浏览器的优势(在Firefox 5、Firefox 10、MSIE 9、MSIE 7、Safari 5、Chrome 9上测试)

/** 将处理程序注册到给定对象的事件。 @param obj将引发事件的对象 @参数evType事件类型:单击、按键、鼠标悬停。。。 @param fn事件处理程序函数 @param isCapturing设置事件模式(true=捕获事件,false=冒泡事件) @如果事件处理程序已正确附加,则返回true */ 功能加法器(obj、evType、fn、isCapturing){ 如果(isCapturing==null)isCapturing=false; if(对象添加列表器){ //火狐 对象添加列表器(evType、fn、isCapturing); 返回true; }else if(对象附件){ //MSIE var r=对象附件('on'+evType,fn); 返回r; }否则{ 返回false; } } //注册到潜在的页面可见性更改 附录(文件,“潜在可视性变化”,功能(事件){ document.getElementById(“x”).innerHTML+=“潜在可视性更改:潜在隐藏=“+document.potentialHidden+”,document.potentialHiddensence=“+document.potentialHiddensence+”s
”; }); //注册到W3C页面可见性API var hidden=null; var visibilityChange=null; if(typeof document.mozHidden!=“未定义”){ hidden=“mozHidden”; visibilityChange=“mozvisibilitychange”; }else if(typeof document.msHidden!=“未定义”){ hidden=“msHidden”; visibilityChange=“msvisibilitychange”; }else if(文档类型.webkitHidden!=“未定义”){ hidden=“webkitshidden”; visibilityChange=“webkitvisibilitychange”; }else if(typeof document.hidden!=“hidden”){ hidden=“hidden”; visibilityChange=“visibilityChange”; } 如果(隐藏!=null&&visib <div id="x"></div> <script> /** Registers the handler to the event for the given object. @param obj the object which will raise the event @param evType the event type: click, keypress, mouseover, ... @param fn the event handler function @param isCapturing set the event mode (true = capturing event, false = bubbling event) @return true if the event handler has been attached correctly */ function addEvent(obj, evType, fn, isCapturing){ if (isCapturing==null) isCapturing=false; if (obj.addEventListener){ // Firefox obj.addEventListener(evType, fn, isCapturing); return true; } else if (obj.attachEvent){ // MSIE var r = obj.attachEvent('on'+evType, fn); return r; } else { return false; } } // register to the potential page visibility change addEvent(document, "potentialvisilitychange", function(event) { document.getElementById("x").innerHTML+="potentialVisilityChange: potentialHidden="+document.potentialHidden+", document.potentiallyHiddenSince="+document.potentiallyHiddenSince+" s<br>"; }); // register to the W3C Page Visibility API var hidden=null; var visibilityChange=null; if (typeof document.mozHidden !== "undefined") { hidden="mozHidden"; visibilityChange="mozvisibilitychange"; } else if (typeof document.msHidden !== "undefined") { hidden="msHidden"; visibilityChange="msvisibilitychange"; } else if (typeof document.webkitHidden!=="undefined") { hidden="webkitHidden"; visibilityChange="webkitvisibilitychange"; } else if (typeof document.hidden !=="hidden") { hidden="hidden"; visibilityChange="visibilitychange"; } if (hidden!=null && visibilityChange!=null) { addEvent(document, visibilityChange, function(event) { document.getElementById("x").innerHTML+=visibilityChange+": "+hidden+"="+document[hidden]+"<br>"; }); } var potentialPageVisibility = { pageVisibilityChangeThreshold:3*3600, // in seconds init:function() { function setAsNotHidden() { var dispatchEventRequired=document.potentialHidden; document.potentialHidden=false; document.potentiallyHiddenSince=0; if (dispatchEventRequired) dispatchPageVisibilityChangeEvent(); } function initPotentiallyHiddenDetection() { if (!hasFocusLocal) { // the window does not has the focus => check for user activity in the window lastActionDate=new Date(); if (timeoutHandler!=null) { clearTimeout(timeoutHandler); } timeoutHandler = setTimeout(checkPageVisibility, potentialPageVisibility.pageVisibilityChangeThreshold*1000+100); // +100 ms to avoid rounding issues under Firefox } } function dispatchPageVisibilityChangeEvent() { unifiedVisilityChangeEventDispatchAllowed=false; var evt = document.createEvent("Event"); evt.initEvent("potentialvisilitychange", true, true); document.dispatchEvent(evt); } function checkPageVisibility() { var potentialHiddenDuration=(hasFocusLocal || lastActionDate==null?0:Math.floor((new Date().getTime()-lastActionDate.getTime())/1000)); document.potentiallyHiddenSince=potentialHiddenDuration; if (potentialHiddenDuration>=potentialPageVisibility.pageVisibilityChangeThreshold && !document.potentialHidden) { // page visibility change threshold raiched => raise the even 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>"; // raised when the page first shows }); addEvent(window, "pagehide", function(event) { document.getElementById("x").innerHTML+="pagehide/win:<br>"; // not raised }); 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 seconds for testing potentialPageVisibility.init(); </script>
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);
}
(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);

})();
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);
});
if(new_message){
    if(!document.hasFocus()){
        audio.play();
        document.title="Have new messages";
    }
    else{
        audio.stop();
        document.title="Application Name";
    } 
}
// If page is visible right now
if( ifvisible.now() ){
  // Display pop-up
  openPopUp();
}
visible    ... page is visible
hidden     ... page is not visible
prerender  ... page is being prerendered by the browser
/* 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();
});
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();
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);
                    });
                }
            }
        }
    };

});
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');
});
document.addEventListener( 'visibilitychange' , function() {
    if (document.hidden) {
        console.log('bye');
    } else {
        console.log('well back');
    }
}, false );
if(!document.hasFocus()) {
    // do stuff
}
document.addEventListener("visibilitychange", function() {
      document.title = document.hidden ? "I'm away" : "I'm here";
});