it-swarm.com.de

Gibt es eine Möglichkeit zu erkennen, ob ein Browserfenster derzeit nicht aktiv ist?

Ich habe JavaScript, das regelmäßig Aktivitäten durchführt. Wenn der Benutzer die Site nicht ansieht (d. H. Das Fenster oder die Registerkarte hat keinen Fokus), wäre es schön, nicht ausgeführt zu werden.

Gibt es eine Möglichkeit, dies mit JavaScript zu tun?

Mein Bezugspunkt: Gmail Chat gibt einen Ton aus, wenn das von Ihnen verwendete Fenster nicht aktiv ist.

547
Luke Francl

Seit dem ursprünglichen Verfassen dieser Antwort hat eine neue Spezifikation dank des W3C den Empfehlungsstatus erreicht . Mit der Page Visibility API (on MDN ) können wir jetzt genauer erkennen, wann eine Seite für den Benutzer verborgen ist.

document.addEventListener("visibilitychange", onchange);

Aktuelle Browserunterstützung:

Der folgende Code greift auf die weniger zuverlässige Unschärfe/Fokus-Methode in inkompatiblen Browsern zurück:

(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 und onfocusout sind erforderlich für IE 9 und niedriger , während alle anderen von onfocus und onblur Gebrauch machen, mit Ausnahme von iOS, das onpageshow und onpagehide verwendet.

650
Andy E

Ich würde jQuery verwenden, weil Sie dann nur noch Folgendes tun müssen:

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

Oder zumindest hat es bei mir funktioniert.

124
Carson Wright

Auf GitHub ist eine ordentliche Bibliothek verfügbar:

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

Beispiel:

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

Ich habe Version 1.0.1 auf allen Browsern getestet und kann bestätigen, dass es funktioniert mit:

  • IE9, IE10
  • FF 26.0
  • Chrome 34.0

... und wahrscheinlich alle neueren Versionen.

Funktioniert nicht vollständig mit:

  • IE8 - zeigt immer an, dass die Registerkarte/das Fenster gerade aktiv ist (.now() gibt für mich immer true zurück)
23
omnomnom

Ich erstelle einen Comet Chat für meine App und wenn ich eine Nachricht von einem anderen Benutzer erhalte, benutze ich:

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

Verwenden von: Page Visibility API

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

Kann ich verwenden? http://caniuse.com/#feat=pagevisibility

15
l2aelba

Ich habe zunächst die Community-Wiki-Antwort verwendet, aber festgestellt, dass Alt-Tab-Ereignisse in Chrome nicht erkannt wurden. Dies liegt daran, dass die erste verfügbare Ereignisquelle verwendet wird. In diesem Fall handelt es sich um die API für die Seitensichtbarkeit, die in Chrome das Alt-Tabbing nicht zu protokollieren scheint.

Ich habe beschlossen, das Skript ein wenig zu modifizieren, um alle mögliche Ereignisse für Änderungen des Seitenfokus zu verfolgen. Hier ist eine Funktion, die Sie einfügen können:

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;
};

Benutze es so:

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

Diese Version lauscht auf alle die verschiedenen Sichtbarkeitsereignisse und löst einen Rückruf aus, wenn einer von ihnen eine Änderung verursacht. Die Handler focused und unfocused stellen sicher, dass der Rückruf nicht mehrmals aufgerufen wird, wenn mehrere APIs dieselbe Sichtbarkeitsänderung feststellen.

11

Das ist wirklich schwierig. Bei den folgenden Anforderungen scheint es keine Lösung zu geben.

  • Die Seite enthält iframes, über die Sie keine Kontrolle haben
  • Sie möchten die Änderung des Sichtbarkeitsstatus unabhängig von der Änderung verfolgen, die durch eine TAB-Änderung (Strg + Tab) oder eine Fensteränderung (Alt + Tab) ausgelöst wird.

Das passiert, weil:

  • Die Page Visibility API kann Sie zuverlässig über eine Änderung der Registerkarte informieren (auch mit Iframes), kann Ihnen jedoch nicht mitteilen, wann der Benutzer das Fenster wechselt.
  • Das Abhören von Fensterverwacklungs-/Fokusereignissen kann Alt + Tabulatoren und Strg + Tabulatoren erkennen, solange der Iframe nicht den Fokus hat.

Angesichts dieser Einschränkungen ist es möglich, eine Lösung zu implementieren, die Folgendes kombiniert: - Die Seiten-Sichtbarkeits-API - Fensterunschärfe/-fokus - document.activeElement

Das ist in der Lage:

  • 1) Strg + Tab, wenn die übergeordnete Seite den Fokus hat: JA
  • 2) Strg + Tab, wenn iframe den Fokus hat: JA
  • 3) Alt + Tab, wenn die übergeordnete Seite den Fokus hat: JA
  • 4) Alt + Tab, wenn iframe den Fokus hat: NO <- blöd

Wenn der Iframe den Fokus hat, werden Ihre Unschärfe-/Fokusereignisse überhaupt nicht aufgerufen, und die Seiten-Sichtbarkeits-API wird nicht auf Alt + Tab ausgelöst.

Ich habe auf @ AndyEs Lösung aufgebaut und diese (fast gute) Lösung hier implementiert: https://dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test1.html (sorry, ich hatte einige Probleme mit JSFiddle).

Dies ist auch auf Github verfügbar: https://github.com/qmagico/estante-components

Dies funktioniert auf Chrom/Chrom. Es funktioniert auf Firefox, außer dass es den Iframe-Inhalt nicht lädt (keine Ahnung warum?)

Um das letzte Problem (4) zu beheben, können Sie nur auf Unschärfe-/Fokusereignisse auf dem Iframe warten. Wenn Sie etwas Kontrolle über die iframes haben, können Sie die postMessage-API verwenden, um dies zu tun.

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

Ich habe das immer noch nicht mit genügend Browsern getestet. Wenn Sie weitere Informationen darüber finden, wo dies nicht funktioniert, lassen Sie es mich bitte in den Kommentaren unten wissen.

7
Tony Lâmpada
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
yckart

das funktioniert bei mir auf chrome 67, firefox 67,

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

In HTML 5 können Sie auch Folgendes verwenden:

  • onpageshow: Skript, das ausgeführt wird, wenn das Fenster sichtbar wird
  • onpagehide: Skript, das ausgeführt wird, wenn das Fenster ausgeblendet ist

Sehen:

3
roberkules

du kannst benutzen:

(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);

})();
3
maryam

Dies ist eine Anpassung der Antwort von Andy E.

Dies erledigt eine Aufgabe, z.B. Aktualisieren Sie die Seite alle 30 Sekunden, jedoch nur, wenn die Seite sichtbar und fokussiert ist.

Wenn die Sicht nicht erkannt werden kann, wird nur der Fokus verwendet.

Wenn der Benutzer die Seite fokussiert, wird sie sofort aktualisiert

Die Seite wird erst 30 Sekunden nach einem Ajax-Aufruf erneut aktualisiert

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);
}
2
roger

Für angle.js ist hier eine Direktive (basierend auf der akzeptierten Antwort), mit der Ihr Controller auf eine Änderung der Sichtbarkeit reagieren kann:

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);
                    });
                }
            }
        }
    };

});

Sie können es wie folgt verwenden: <div react-on-window-focus="refresh()">, wobei refresh() eine Bereichsfunktion im Bereich des Controllers ist, der sich im Bereich befindet.

1
Steve Campbell

Eine Lösung ohne jQuery finden Sie unter Visibility.js , das Informationen zu drei Seitenzuständen enthält

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

und auch Convenience-Wrapper für 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();
});

Ein Fallback für ältere Browser (IE <10; iOS <7) ist ebenfalls verfügbar

1
Niko

Etwas komplizierter wäre es, die Mausposition mit setInterval() zu überprüfen und mit der letzten Prüfung zu vergleichen. Wenn sich die Maus in einer festgelegten Zeit nicht bewegt hat, ist der Benutzer wahrscheinlich untätig.

Dies hat den zusätzlichen Vorteil, dass angezeigt wird, ob sich der Benutzer im Leerlauf befindet, anstatt nur zu prüfen, ob das Fenster nicht aktiv ist.

Wie viele Leute bereits darauf hingewiesen haben, ist dies nicht immer eine gute Möglichkeit, um zu überprüfen, ob der Benutzer oder das Browserfenster inaktiv ist, da der Benutzer möglicherweise nicht einmal die Maus verwendet oder ein Video oder ähnliches ansieht. Ich schlage nur einen möglichen Weg vor, um auf Leerlauf zu prüfen.

1
Austin Hyde

Wollte nur hinzufügen: Die Frage ist nicht klar geschrieben. "Wenn der Benutzer die Site nicht ansieht (d. H. Das Fenster oder die Registerkarte hat keinen Fokus) ..."

Ich kann mir eine Site ansehen, wenn sie nicht fokussiert ist. Die meisten Desktop-Systeme können Fenster parallel anzeigen :)

Aus diesem Grund ist das Page Visibility API wahrscheinlich die richtige Antwort, da es das Aktualisieren der Site verhindert, wenn der "Benutzer keine Aktualisierungen sehen kann", die sich stark von "Registerkarte hat keinen Fokus" unterscheiden können.

0
HolgerJeromin

Wenn Sie handeln möchten ein ganz Browser-Unschärfe: Wie ich kommentiert habe, wird, wenn der Browser den Fokus verliert, keines der vorgeschlagenen Ereignisse ausgelöst. Meine Idee ist, in einer Schleife hochzuzählen und den Zähler zurückzusetzen, wenn ein Ereignis ausgelöst wird. Wenn der Zähler ein Limit erreicht, mache ich eine location.href auf eine andere Seite. Dies wird auch ausgelöst, wenn Sie an Entwicklungswerkzeugen arbeiten.

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();

Dies ist ein Entwurf, der erfolgreich auf FF getestet wurde.

0
B.F.