Is there a way to detect if a browser window is not currently active?

前端 未结 19 2045
无人共我
无人共我 2020-11-21 04:40

I have JavaScript that is doing activity periodically. When the user is not looking at the site (i.e., the window or tab does not have focus), it\'d be nice to not run.

相关标签:
19条回答
  • 2020-11-21 04:52

    this worked for me

    document.addEventListener("visibilitychange", function() {
          document.title = document.hidden ? "I'm away" : "I'm here";
    });
    

    demo: https://iamsahilralkar.github.io/document-hidden-demo/

    0 讨论(0)
  • 2020-11-21 04:54

    This is an adaptation of the answer from Andy E.

    This will do a task e.g. refresh the page every 30 seconds, but only if the page is visible and focused.

    If visibility can't be detected, then only focus will be used.

    If the user focuses the page, then it will update immediately

    The page won't update again until 30 seconds after any ajax call

    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);
    }
    
    0 讨论(0)
  • 2020-11-21 04:55

    u can use :

    (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);
    
    })();
    
    0 讨论(0)
  • 2020-11-21 05:00

    A slightly more complicated way would be to use setInterval() to check mouse position and compare to last check. If the mouse hasn't moved in a set amount of time, the user is probably idle.

    This has the added advantage of telling if the user is idle, instead of just checking if the window is not active.

    As many people have pointed out, this is not always a good way to check whether the user or browser window is idle, as the user might not even be using the mouse or is watching a video, or similar. I am just suggesting one possible way to check for idle-ness.

    0 讨论(0)
  • 2020-11-21 05:01

    This is really tricky. There seems to be no solution given the following requirements.

    • The page includes iframes that you have no control over
    • You want to track visibility state change regardless of the change being triggered by a TAB change (ctrl+tab) or a window change (alt+tab)

    This happens because:

    • The page Visibility API can reliably tell you of a tab change (even with iframes), but it can't tell you when the user changes windows.
    • Listening to window blur/focus events can detect alt+tabs and ctrl+tabs, as long as the iframe doesn't have focus.

    Given these restrictions, it is possible to implement a solution that combines - The page Visibility API - window blur/focus - document.activeElement

    That is able to:

    • 1) ctrl+tab when parent page has focus: YES
    • 2) ctrl+tab when iframe has focus: YES
    • 3) alt+tab when parent page has focus: YES
    • 4) alt+tab when iframe has focus: NO <-- bummer

    When the iframe has focus, your blur/focus events don't get invoked at all, and the page Visibility API won't trigger on alt+tab.

    I built upon @AndyE's solution and implemented this (almost good) solution here: https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test1.html (sorry, I had some trouble with JSFiddle).

    This is also available on Github: https://github.com/qmagico/estante-components

    This works on chrome/chromium. It kind works on firefox, except that it doesn't load the iframe contents (any idea why?)

    Anyway, to resolve the last problem (4), the only way you can do that is to listen for blur/focus events on the iframe. If you have some control over the iframes, you can use the postMessage API to do that.

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

    I still haven't tested this with enough browsers. If you can find more info about where this doesn't work, please let me know in the comments below.

    0 讨论(0)
  • 2020-11-21 05:03

    I would use jQuery because then all you have to do is this:

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

    Or at least it worked for me.

    0 讨论(0)
提交回复
热议问题