Rileva se la scheda Browser ha lo stato attivo


149

Esiste un modo affidabile tra browser per rilevare l'attivazione di una scheda.

Lo scenario è che abbiamo un'applicazione che esegue regolarmente il polling per i prezzi delle azioni, e se la pagina non ha il focus potremmo fermare il polling e salvare tutti il ​​rumore del traffico, specialmente perché le persone sono fan di aprire diverse schede con diversi portafogli.

È window.onblure window.onfocusun'opzione per questo?


Risposte:


127

Sì, window.onfocuse window.onblurdovrebbe funzionare per il tuo scenario:

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


3
L'aspetto onfocusin / onfocusout di questo, e anche la nota su come dire all'utente che hai messo in pausa sono davvero buone note. Grazie.
Fenton,

7
Si noti che non è possibile distinguere tra la pagina attiva o inattiva al caricamento della pagina in questo modo.
pimvdb,

@SteveFenton - onfocusè crossbrowser, dove gli eventi che hai citato sono solo IE, non riesco a capire perché questo sia considerato una buona nota da te ..
vsync,

1
@vsync - leggi l'articolo collegato, vedrai che usa sia 'onfocusin' che 'onfocus'.
Fenton,

Potresti almeno menzionare la differenza tra i due?
Lenar Hoyt,

53

Modifica importante: questa risposta è obsoleta. Da quando è stato scritto, l'API di visibilità ( mdn , esempio , specifiche ) è stata introdotta. È il modo migliore per risolvere questo problema.


var focused = true;

window.onfocus = function() {
    focused = true;
};
window.onblur = function() {
    focused = false;
};

AFAIK, focuse blursono tutti supportati su ... tutto. (vedi http://www.quirksmode.org/dom/events/index.html )


2
Solo una piccola nota, con tutte queste soluzioni, si corre il rischio che l'utente cambi scheda prima che il javascript sia completamente caricato, assegnando così il valore sbagliato a focalizzato. Non sono sicuro che ci sia un buon modo per aggirarlo.
JayD3e

I collegamenti di aggiornamento sono esattamente quello che stavo cercando. Grazie per averli aggiunti!
webLacky3rdClass

La domanda riguarda in particolare il rilevamento di uno stato attivo della pagina, che è diverso dal rilevamento della visibilità della pagina. Più pagine possono essere visibili contemporaneamente (in finestre diverse), mentre solo una può avere lo stato attivo. Usa la tecnica adatta alle tue esigenze, ma conosci la differenza.
jaredjacobs,

1
Questa è una soluzione pericolosa perché corre il rischio di ignorare altri listener di eventi in un'applicazione più grande. Si dovrebbe invece seguire questa risposta: stackoverflow.com/a/21935031/549503
mmmeff

51

Durante la ricerca di questo problema, ho trovato una raccomandazione sull'utilizzo dell'API di visibilità della pagina . I browser più moderni supportano questa API secondo Can I Use: http://caniuse.com/#feat=pagevisibility .

Ecco un esempio funzionante (derivato da questo frammento ):

$(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];
    }
  });
});

Aggiornamento: l'esempio sopra usato aveva prefisso le proprietà per i browser Gecko e WebKit, ma ho rimosso l'implementazione perché questi browser offrono l'API di visibilità della pagina senza prefisso da un po 'di tempo. Ho mantenuto il prefisso specifico di Microsoft per rimanere compatibile con IE10.


Quando i prefissi del fornitore passeranno da questo, probabilmente cambierò!
Fenton,

L'unico vero problema con questo non sono i prefissi del fornitore perché c'è una raccomandazione ufficiale del W3C (datata 29. ottobre 2013). In alcuni casi, il problema è che l'API di visibilità della pagina è supportata in IE10 e versioni successive. Se devi supportare IE9, dovresti cercare un approccio diverso ...
Ilija,

Questo è il modo corretto di farlo per tutti i browser moderni. +1
Ajedi32,

Sei sicuro che questi prefissi del fornitore siano persino necessari? Secondo MDN e CanIUse, non sono stati necessari su Chrome dalla versione 32 o su Firefox dalla versione 17 e non sono mai stati necessari su IE.
Ajedi32,

@Ajedi32 Grazie. Dovrò fare alcuni test e scavare per vedere cosa è ancora rilevante e cosa può essere lasciato fuori ora.
Ilija,

37

Sorprendente vedere nessuno menzionato document.hasFocus

if (document.hasFocus()) console.log('Tab is active')

MDN ha ulteriori informazioni.


funziona per me (testato su Chrome e Firefox). La risposta accettata (onfocus / onblur) non ha funzionato
danno il

La risposta corretta ancora una volta in fondo. Ben fatto StackOverflow!
Eleven October

davvero, non è questa la risposta perfetta? qualcuno vede qualche svantaggio?
gaspar

2
L'unico aspetto negativo di questo è che se stai cercando di determinare se la scheda è attiva all'interno di un iframe, fallirebbe nel caso in cui l'iframe fosse caricato quando la pagina principale era ancora fuori fuoco. Per coprire anche quello dovrai andare con l'API di visibilità della pagina.
Ivan

29

Sì, quelli dovrebbero funzionare per te. Mi hai appena ricordato questo link che ho trovato che sfrutta quelle tecniche. lettura interessante


2
+1 - è un trucco molto intelligente, immagino che possa ingannare molte persone.
Fenton,

2
Che attacco ingegnoso e subdolo. Interessante leggere che, grazie.
Voo,

4

Lo farei in questo modo (riferimento 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
        }

    };  

Puoi spiegare in che modo questa risposta differisce dalla risposta data da @Ilia - potrebbe esserci una differenza, ma è sottile - quindi una spiegazione di cosa sia e perché dovrebbe essere diversa sarebbe apprezzata.
Fenton,

2

Cross Browser jQuery Solution! Raw disponibile su GitHub

Divertente e facile da usare!

Il seguente plugin eseguirà il test standard per varie versioni di IE, Chrome, Firefox, Safari, ecc. E stabilirà i metodi dichiarati di conseguenza. Si occupa anche di problemi come:

  • onblur | .blur / onfocus | .focus " duplicato chiamate "
  • la finestra perde attenzione attraverso la selezione di app alternative, come la parola
    • Questo tende ad essere indesiderabile semplicemente perché, se hai una pagina di banca aperta, ed è un evento onblur che le dice di mascherare la pagina, quindi se apri la calcolatrice, non puoi più vedere la pagina!
  • Non si attiva al caricamento della pagina

L'uso è semplice come: Scorri verso il basso fino a " Esegui snippet "

$.winFocus(function(event, isVisible) {
    console.log("Combo\t\t", event, isVisible);
});

//  OR Pass False boolean, and it will not trigger on load,
//  Instead, it will first trigger on first blur of current tab_window
$.winFocus(function(event, isVisible) {
    console.log("Combo\t\t", event, isVisible);
}, false);

//  OR Establish an object having methods "blur" & "focus", and/or "blurFocus"
//  (yes, you can set all 3, tho blurFocus is the only one with an 'isVisible' param)
$.winFocus({
    blur: function(event) {
        console.log("Blur\t\t", event);
    },
    focus: function(event) {
        console.log("Focus\t\t", event);
    }
});

//  OR First method becoms a "blur", second method becoms "focus"!
$.winFocus(function(event) {
    console.log("Blur\t\t", event);
},
function(event) {
    console.log("Focus\t\t", event);
});

/*    Begin Plugin    */
;;(function($){$.winFocus||($.extend({winFocus:function(){var a=!0,b=[];$(document).data("winFocus")||$(document).data("winFocus",$.winFocus.init());for(x in arguments)"object"==typeof arguments[x]?(arguments[x].blur&&$.winFocus.methods.blur.push(arguments[x].blur),arguments[x].focus&&$.winFocus.methods.focus.push(arguments[x].focus),arguments[x].blurFocus&&$.winFocus.methods.blurFocus.push(arguments[x].blurFocus),arguments[x].initRun&&(a=arguments[x].initRun)):"function"==typeof arguments[x]?b.push(arguments[x]):
"boolean"==typeof arguments[x]&&(a=arguments[x]);b&&(1==b.length?$.winFocus.methods.blurFocus.push(b[0]):($.winFocus.methods.blur.push(b[0]),$.winFocus.methods.focus.push(b[1])));if(a)$.winFocus.methods.onChange()}}),$.winFocus.init=function(){$.winFocus.props.hidden in document?document.addEventListener("visibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="mozHidden")in document?document.addEventListener("mozvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden=
"webkitHidden")in document?document.addEventListener("webkitvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="msHidden")in document?document.addEventListener("msvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="onfocusin")in document?document.onfocusin=document.onfocusout=$.winFocus.methods.onChange:window.onpageshow=window.onpagehide=window.onfocus=window.onblur=$.winFocus.methods.onChange;return $.winFocus},$.winFocus.methods={blurFocus:[],blur:[],focus:[],
exeCB:function(a){$.winFocus.methods.blurFocus&&$.each($.winFocus.methods.blurFocus,function(b,c){this.apply($.winFocus,[a,!a.hidden])});a.hidden&&$.winFocus.methods.blur&&$.each($.winFocus.methods.blur,function(b,c){this.apply($.winFocus,[a])});!a.hidden&&$.winFocus.methods.focus&&$.each($.winFocus.methods.focus,function(b,c){this.apply($.winFocus,[a])})},onChange:function(a){var b={focus:!1,focusin:!1,pageshow:!1,blur:!0,focusout:!0,pagehide:!0};if(a=a||window.event)a.hidden=a.type in b?b[a.type]:
document[$.winFocus.props.hidden],$(window).data("visible",!a.hidden),$.winFocus.methods.exeCB(a);else try{$.winFocus.methods.onChange.call(document,new Event("visibilitychange"))}catch(c){}}},$.winFocus.props={hidden:"hidden"})})(jQuery);
/*    End Plugin      */

// Simple example
$(function() {
	$.winFocus(function(event, isVisible) {
		$('td tbody').empty();
		$.each(event, function(i) {
			$('td tbody').append(
				$('<tr />').append(
					$('<th />', { text: i }),
					$('<td />', { text: this.toString() })
				)
			)
		});
		if (isVisible) 
			$("#isVisible").stop().delay(100).fadeOut('fast', function(e) {
				$('body').addClass('visible');
				$(this).stop().text('TRUE').fadeIn('slow');
			});
		else {
			$('body').removeClass('visible');
			$("#isVisible").text('FALSE');
		}
	});
})
body { background: #AAF; }
table { width: 100%; }
table table { border-collapse: collapse; margin: 0 auto; width: auto; }
tbody > tr > th { text-align: right; }
td { width: 50%; }
th, td { padding: .1em .5em; }
td th, td td { border: 1px solid; }
.visible { background: #FFA; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h3>See Console for Event Object Returned</h3>
<table>
    <tr>
        <th><p>Is Visible?</p></th>
        <td><p id="isVisible">TRUE</p></td>
    </tr>
    <tr>
        <td colspan="2">
            <table>
                <thead>
                    <tr>
                        <th colspan="2">Event Data <span style="font-size: .8em;">{ See Console for More Details }</span></th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </td>
    </tr>
</table>


Dovresti mettere il codice non minimizzato per il plugin.
Patrick Desjardins,

@PatrickDesjardins sì. Pensa di farlo questo fine settimana insieme ad altre cose. IO? Dai un'occhiata a un mucchio di cose che ho. Jdmckinstry a Github. Aggiungerò collegamenti a vecchie risposte come queste man mano che le aggiungo a gist
SpYk3HH,

Cosa succede se voglio che la pagina perda lo stato attivo quando passo a un'altra app, come "Word" o "Calcolatrice"?
Benas,

@Benas Potrebbe essere sbagliato, ma credo che sia la funzionalità di base di base jQuery(window).blur/focus, che è stata indesiderata da molti, quindi uno dei motivi per cui ho creato questo plugin. Il plug-in ha lo scopo di fornire ciò che jQuery non ha già
SpYk3HH il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.