704 votes

Y a-t-il un moyen de détecter si une fenêtre de navigateur n’est pas active ?

J’ai le code JavaScript qui fait périodiquement l’activité. Lorsque l’utilisateur n’est pas à la recherche sur le site (c'est-à-dire, la fenêtre ou l’onglet n’a pas focus), il serait agréable de ne fonctionne pas.

Est-il possible de le faire à l’aide de JavaScript ?

Mon point de référence : GMail Chat joue un son si la fenêtre que vous utilisez n’est pas active.

790voto

Andy E Points 132925

Depuis l'origine de l'écriture de cette réponse, un nouveau cahier des charges ont atteint la recommandation d'état de grâce pour le W3C. La Page de la Visibilité de l'API nous permet désormais de détecter plus précisément lorsqu'une page est caché à l'utilisateur.

Actuelle de la prise en charge du navigateur:

Le code suivant permet l'utilisation de l'API, de revenir à la moins fiable de flou/mise au point de la méthode dans les navigateurs incompatibles.

(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
    onchange({type:(document.visibilityState == "visible") ? "focus" : "blur"})        
})();

onfocusin et onfocusout sont requis pour IE 9 et inférieur, tandis que tous les autres font usage de onfocus et onblur, sauf pour iOS, qui utilise onpageshow et onpagehide.

143voto

Carson Wright Points 535

Je voudrais utiliser jQuery parce qu’alors tout ce que vous avez à faire est la suivante :

Ou au moins cela a fonctionné pour moi.

64voto

Julien Kronegg Points 784

Le W3C Page de la Visibilité de l'API est ce que vous cherchez (c'est à dire de déterminer si l'utilisateur peut voir la page). Mais il est actuellement pris en charge uniquement sous les navigateurs suivants:

  • Firefox 10
  • MSIE 10
  • Chrome 13

D'autres méthodes ne fonctionnera pas, par exemple :

  • À l'aide de focus/flou base de méthodes vous donne beaucoup de faux positifs. Par exemple, si l'utilisateur affiche une petite fenêtre en haut de la fenêtre du navigateur, la fenêtre du navigateur va perdre le focus (onblur relevés) mais l'utilisateur est toujours en mesure de le voir (il a toujours besoin d'être actualisé). Voir aussi http://javascript.info/tutorial/focus
  • En s'appuyant sur l'activité de l'utilisateur (déplacement de la souris, les clics, les clés tapés) vous donne beaucoup de faux positifs. Pensez à le même cas que ci-dessus, ou un utilisateur de regarder une vidéo.

J'utilise une combinaison de la concentration, de flou et de l'activité de l'utilisateur méthodes afin de réduire le taux de faux positifs. Lorsque le document perdre le focus, l'activité de l'utilisateur (comme le mouvement de la souris) sur le document est surveillé afin de déterminer si la fenêtre est visible ou non. La page de la visibilité de probabilité est inversement proportionnelle au temps de la dernière activité de l'utilisateur sur la page: si l'utilisateur ne fait aucune activité sur le document pour une longue période de temps, la page n'est probablement pas visible. Le code ci-dessous imite le W3C Page de la Visibilité de l'API: il se comporte de la même manière, mais a un faible taux de faux positifs. Il a l'avantage d'être multibrowser (testé sur Firefox 5, Firefox 10, MSIE 9, MSIE 7, Safari 5, Chrome 9).


 <div id="x"></div>

<script>
/**
 Inscrit le gestionnaire à l'événement de l'objet donné.
 @param obj l'objet qui va déclencher l'événement
 @param evType le type de l'événement: cliquez sur, touche, souris, ...
 @param fn la fonction de gestionnaire d'événement
 @param isCapturing définir l'événement mode (vrai = la capture de l'événement, false = événement de propagation)
 @return true si le gestionnaire d'événement a été fixé correctement
*/
 fonction addEvent(obj, evType, fn, isCapturing){
 si (isCapturing==null) isCapturing=false; 
 if (obj.la méthode addEventListener){
 // Firefox
 obj.la méthode addEventListener(evType, fn, isCapturing);
 return true;
 } else if (obj.attachEvent){
 // MSIE
 var r = obj.attachEvent('on'+evType, fn);
 return r;
 } else {
 return false;
}
}

 // enregistrer pour le potentiel de la page de visibilité changement
 addEvent(document, "potentialvisilitychange", function(event) {
 document.getElementById("x").innerHTML+="potentialVisilityChange: potentialHidden="+document.potentialHidden+", document.potentiallyHiddenSince="+document.potentiallyHiddenSince+" s
"; }); // enregistrer pour le W3C Page de la Visibilité de l'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.caché !=="caché") { hidden="hidden"; visibilityChange="visibilitychange"; } si (caché!=null && visibilityChange!=null) { addEvent(document, visibilityChange, function(event) { document.getElementById("x").innerHTML+=visibilityChange+": "+cachée+"="+document[hidden]+"
"; }); } var potentialPageVisibility = { pageVisibilityChangeThreshold:3*3600, // dans quelques secondes init:function() { fonction setAsNotHidden() { var dispatchEventRequired=document.potentialHidden; document.potentialHidden=false; document.potentiallyHiddenSince=0; si (dispatchEventRequired) dispatchPageVisibilityChangeEvent(); } fonction initPotentiallyHiddenDetection() { if (!hasFocusLocal) { // la fenêtre n'a pas le focus => vérifier l'activité de l'utilisateur dans la fenêtre lastActionDate=new Date(); si (timeoutHandler!=null) { clearTimeout(timeoutHandler); } timeoutHandler = setTimeout(checkPageVisibility, potentialPageVisibility.pageVisibilityChangeThreshold*1000+100); // +100 ms pour éviter l'arrondi sous Firefox } } fonction dispatchPageVisibilityChangeEvent() { unifiedVisilityChangeEventDispatchallowed=false; var evt = document.createEvent("Événement"); evt.initEvent("potentialvisilitychange", true, true); document.dispatchEvent(evt); } fonction checkPageVisibility() { var potentialHiddenDuration=(hasFocusLocal || lastActionDate==null?0:les Maths.floor((new Date().getTime()-lastActionDate.getTime())/1000)); document.potentiallyHiddenSince=potentialHiddenDuration; si (potentialHiddenDuration>=potentialPageVisibility.pageVisibilityChangeThreshold && !document.potentialHidden) { // la page de la visibilité de changement de seuil raiched => augmenter la même 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:
"; }); addEvent(document, "pagehide", function(event) { document.getElementById("x").innerHTML+="pagehide/doc:
"; }); addEvent(fenêtre, "pageshow", function(event) { document.getElementById("x").innerHTML+="pageshow/win:
"; // soulevées lorsque la page montre }); addEvent(fenêtre, "pagehide", function(event) { document.getElementById("x").innerHTML+="pagehide/win:
"; // pas soulevé }); 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(fenêtre, "flou", function(event) { hasFocusLocal=false; initPotentiallyHiddenDetection(); }); addEvent(fenêtre, "focus", function(event) { hasFocusLocal=true; setAsNotHidden(); }); setAsNotHidden(); } } potentialPageVisibility.pageVisibilityChangeThreshold=4; // pour le test potentialPageVisibility.init(); </script>

Comme il n'existe actuellement pas de travail cross-browser solution sans faux-positif, vous feriez mieux de réfléchir à deux fois sur la désactivation de périodiques sur l'activité de votre site web.

28voto

Piotrek De Points 3566

Il s'agit d'un pur bibliothèque disponible sur GitHub:

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

Exemple:

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

J'ai testé la version 1.0.1 sur tous les navigateurs que j'ai et je peux confirmer que cela fonctionne avec:

  • IE9, IE10
  • FF 26.0
  • Chrome 34.0

... et probablement toutes les versions plus récentes.

Ne fait pas de bien travailler avec:

  • IE8 - toujours indiquer que l'onglet/fenêtre actuellement active (.now() retourne toujours true pour moi)

21voto

SpYk3HH Points 10533

La réponse sommet des rochers et c'est ce qui a conduit à ma réponse, de sorte que même si vous trouvez ma réponse grande, peut-être plus l'un de l'inspiration?

Je suis tout simplement jeter mes 2cents ici parce que j'ai trouvé beaucoup d'autres réponses que la moitié ont travaillé, mais devrait être évitée. J'ai également reconstruit la réponse sommet, sous forme de Plugin jQuery avec la facilité d'utilisation et un travail de Violon pour montrer combien il est simple!

Tout d'abord, l'une des communes les réponses que j'ai vu ici et dans dup de cette question est le jQuery $(window).focus/blur méthodes. 2 les problèmes persistent avec cette méthode.

Le premier problème est un problème de "duplicate" appels. C'est assez facile à contourner si vous souhaitez utiliser cette méthode. Il suffit de créer une sorte d'identifiant de vérifier à chaque fois que votre fonction est appelée, puis aller à la ville. Par Exemple:

$(window).on("blur focus", function(e) {
    var prevType = $(this).data("prevType"); // getting identifier to check by
    if (prevType != e.type) {   //  reduce double fire issues by checking identifier
        switch (e.type) {
            case "blur":
                // do work
                break;
            case "focus":
                // do work
                break;
        }
    }
    $(this).data("prevType", e.type); // reset identifier
})

Aussi simple que cela semble, il renvoie à un nouveau problème. Pour jQuery, fenêtre.focus moyens lorsque l'utilisateur a fait "choisi" de cette fenêtre. En d'autres termes, si l'utilisateur sélectionne une autre application (comme la calculatrice ou quelque chose) ou même de clics dans le navigateur de la console, la fenêtre perd le focus". Ainsi, cette méthode peut encore être indésirable.

Ainsi, nous sommes de retour à la méthode prévue par le haut de réponse. Super réponse! Il représente pour ces questions en devenant directement déterminées par les événements. C'est ce qui m'a amené à être en mesure de faire un très facile à utiliser le plugin jQuery qui va être beaucoup plus précis que $(window).blur.

jsFiddle/jQPlug-en

Utilisation:

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

//  OR *new option*

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

//  OR

$.winFocus({
    blur: function(event) {
        console.log("Blur\t\t", event);
    },
    focus: function(event) {
        console.log("Focus\t\t", event);
    }
});

//  OR

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

Le Plugin a été mis à jour!
A maintenant une option "initRun". C'est par défaut à true et exécuter vous êtes à la fonction de changement lors de l'initialisation. Il suffit d'ajouter un false booléen à l'appel, comme $.winFocus(func..., false) prendre un pas en arrière et ne pas avoir de courir jusqu'à la première fois que la fenêtre est centrée ou floue (la plupart des likly floue) après l'appel initial.

Aussi, je crois que j'ai corrigé tous les problèmes de navigateur. Hit me up dans les commentaires si vous trouvez un problème!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X