web-dev-qa-db-fra.com

l'événement changechange de visibilité n'est pas déclenché lors du changement de programme / fenêtre avec ALT + TAB ou en cliquant dans la barre des tâches

Le problème vient du comportement de l'événement "visibilitéchange".

Il est déclenché: - Lorsque je passe à un onglet différent dans la fenêtre du navigateur.

  • Lorsque je clique sur les boutons de réduction/restauration de la fenêtre du navigateur.

(c'est ok)

Ce n'est pas déclenché: - Quand je passe à une autre fenêtre/programme en utilisant ALT + TAB.

  • Lorsque je passe à une autre fenêtre/programme en cliquant sur la barre des tâches.

(cela DEVRAIT se déclencher, car, tout comme lors de la minimisation, la visibilité de la fenêtre peut changer)


Documentation de l'API de visibilité de la page W3 : http://www.w3.org/TR/page-visibility/

Il n'y a pas de définition de "visibilité de la page" concernant ALT+TAB/ changement de programme dans la fiche technique. Je suppose que cela a quelque chose à voir entre le système d'exploitation et le navigateur.


TESTÉ DANS

  • Navigateurs : Chrome 40.0.2214.115 m/Firefox 36.0.1/Internet Explorer 11.0.9600.17107
  • [~ # ~] os [~ # ~] : Windows 8.1

Existe-t-il une solution de contournement pour résoudre ce problème? L'implémentation est assez simple, j'écoute l'événement "visibilitéchange" en utilisant jQuery, puis dans son rappel, je vérifie la valeur de "document.visibilityState", mais le problème est que l'événement ne se déclenche pas comme prévu.

$(document).on('visibilitychange', function() {

    if(document.visibilityState == 'hidden') {
        // page is hidden
    } else {
        // page is visible
    }
});

Cela peut aussi être fait sans jQuery, mais le ALT+TAB et le comportement attendu/masqué de la barre des tâches est toujours manquant:

if(document.addEventListener){
    document.addEventListener("visibilitychange", function() {
        // check for page visibility
    });
}

J'ai également essayé le module ifvisible.js ( https://github.com/serkanyersen/ifvisible.js ) mais le comportement est le même.

ifvisible.on('blur', function() {
    // page is hidden
});

ifvisible.on('focus', function() {
    // page is visible
});

Je n'ai pas testé dans d'autres navigateurs, car si je ne peux pas le faire fonctionner dans Chrome sous Windows, je ne me soucie vraiment pas encore des autres navigateurs.

Une aide ou des suggestions?


METTRE À JOUR

J'ai essayé d'utiliser différents préfixes de fournisseurs pour le nom de l'événement (visibilitéchange, webkitvisibilitychange, mozvisibilitychange, msvisibilitychange) mais mais toujours l'événement n'est pas déclenché lorsque je passe à un autre programme dans la barre des tâches ou ALT+TAB, ou même si j'ouvre le menu Démarrer dans Windows avec la touche Windows, qui couvre tout l'écran.

Je peux reproduire exactement le même problème dans Chrome, Firefox et Internet Explorer.

MISE À JOUR # 2

Voici un article récapitulatif que j'ai écrit pour ce problème et une solution de contournement en Javascript pur pour résoudre les problèmes rencontrés.

MISE À JOUR # 3

Modifié pour inclure une copie de l'article de blog source. (voir réponse acceptée)

27
agbb

Voici un article récapitulatif que j'ai écrit pour ce problème et une solution de contournement en javascript pur pour résoudre les problèmes rencontrés.

Modifié pour inclure une copie de l'article de blog source:


Dans tout type d'application javascript que nous développons, il peut y avoir une fonctionnalité ou un changement dans l'application qui réagit en fonction de l'état de visibilité de l'utilisateur actuel, cela pourrait être de mettre en pause une vidéo en cours de lecture lorsque l'utilisateur ALT + TABs vers une autre fenêtre, suivi des statistiques sur la façon dont les utilisateurs interagissent avec notre application, à quelle fréquence le fait-il basculer vers un autre onglet, combien de temps cela lui prend-il pour revenir et de nombreuses améliorations de performances qui peuvent bénéficier de ce type d'API.

L'API de visibilité de page nous fournit deux attributs de premier niveau: document.hidden (booléen) et document.visibilityState (qui pourrait être n'importe laquelle de ces chaînes: "caché", "visible", "prérendeur", "déchargé"). Cela ne serait pas suffisant sans un événement que nous pourrions écouter, c'est pourquoi l'API fournit également l'événement utile de changement de visibilité.

Voici donc un exemple de base sur la façon dont nous pourrions agir sur un changement de visibilité:

function handleVisibilityChange() {
  if(document.hidden) {
    // the page is hidden
  } else {
    // the page is visible
  }
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);

Nous pourrions également vérifier la valeur de document.visibilityState.

Traiter les problèmes des fournisseurs George Berkeley par John Smibert

Certaines implémentations sur certains navigateurs nécessitent toujours que les attributs ou même le nom de l'événement soient préfixés par le fournisseur, cela signifie que nous pouvons avoir besoin d'écouter l'événement msvisibilitychange ou de rechercher les attributs document.webkitHidden ou document.mozHidden. Pour ce faire, nous devons vérifier si un attribut préfixé par le vendeur est défini, et une fois que nous savons lequel est celui utilisé dans le navigateur actuel (uniquement s'il y a besoin d'un préfixe), nous pouvons nommer l'événement et les attributs correctement.

Voici un exemple d'approche sur la façon de gérer ces préfixes:

var browserPrefixes = ['moz', 'ms', 'o', 'webkit'];

// get the correct attribute name
function getHiddenPropertyName(prefix) {
  return (prefix ? prefix + 'Hidden' : 'hidden');
}

// get the correct event name
function getVisibilityEvent(prefix) {
  return (prefix ? prefix : '') + 'visibilitychange';
}

// get current browser vendor prefix
function getBrowserPrefix() {
  for (var i = 0; i < browserPrefixes.length; i++) {
    if(getHiddenPropertyName(browserPrefixes[i]) in document) {
      // return vendor prefix
      return browserPrefixes[i];
    }
  }

  // no vendor prefix needed
  return null;
}

// bind and handle events
var browserPrefix = getBrowserPrefix();

function handleVisibilityChange() {
  if(document[getHiddenPropertyName(browserPrefix )]) {
    // the page is hidden
    console.log('hidden');
  } else {
    // the page is visible
    console.log('visible');
  }
}

document.addEventListener(getVisibilityEvent(browserPrefix), handleVisibilityChange, false);

Autres problèmes La définition de la "visibilité de la page" pose un problème: comment déterminer si l'application est visible ou non si le focus de la fenêtre est perdu pour une autre fenêtre, mais pas la visibilité réelle à l'écran? Qu'en est-il des différents types de visibilité perdus, comme ALT + TAB, touche WIN/MAC (menu démarrer/tiret), actions de la barre des tâches/du dock, WIN + L (écran de verrouillage), réduction de la fenêtre, fermeture de la fenêtre, changement d'onglet. Qu'en est-il du comportement sur les appareils mobiles?

Il y a beaucoup de façons dont nous pouvons perdre ou gagner en visibilité et beaucoup d'interactions possibles entre le navigateur et le système d'exploitation, donc je ne pense pas qu'il y ait une définition correcte et complète de "page visible" dans les spécifications du W3C. Voici la définition que nous obtenons pour l'attribut document.hidden:

ATTRIBUT CACHÉ Lors de l'obtention, l'attribut caché DOIT retourner vrai si le document contenu par le contexte de navigation de niveau supérieur (fenêtre racine dans la fenêtre du navigateur) [HTML5] n'est pas visible du tout. L'attribut DOIT retourner faux si le document contenu par le contexte de navigation de niveau supérieur est au moins partiellement visible sur au moins un écran.

Si la vue par défaut du document est nulle, lors de l'obtention, l'attribut caché DOIT retourner vrai.

Pour prendre en charge les outils d'accessibilité qui sont généralement en plein écran mais qui affichent toujours une vue de la page, le cas échéant, cet attribut PEUT retourner faux lorsque l'agent utilisateur n'est pas minimisé mais est complètement masqué par d'autres applications.

J'ai trouvé plusieurs incohérences sur le moment où l'événement est réellement déclenché, par exemple (Chrome 41.0.2272.101 m, sur Windows 8.1) l'événement n'est pas déclenché lorsque j'ALT + TAB vers une autre fenêtre/programme ou lorsque je ALT + TAB à nouveau pour revenir, mais il IS déclenché si je CTRL + TAB puis CTRL + MAJ + TAB pour basculer entre les onglets du navigateur. Il est également déclenché lorsque je clique sur le bouton de réduction, mais il n'est pas déclenché si la fenêtre n'est pas agrandie et je clique sur ma fenêtre d'éditeur qui est derrière la fenêtre du navigateur. Le comportement de cette API et ses différentes implémentations sont donc encore obscurs.

Une solution de contournement pour cela consiste à compenser en tirant parti des événements de mise au point et de flou mieux implémentés et en adoptant une approche personnalisée de l'ensemble du problème de "visibilité de la page" à l'aide d'un indicateur interne pour empêcher plusieurs exécutions, voici ce que j'ai trouvé :

var browserPrefixes = ['moz', 'ms', 'o', 'webkit'],
    isVisible = true; // internal flag, defaults to true

// get the correct attribute name
function getHiddenPropertyName(prefix) {
  return (prefix ? prefix + 'Hidden' : 'hidden');
}

// get the correct event name
function getVisibilityEvent(prefix) {
  return (prefix ? prefix : '') + 'visibilitychange';
}

// get current browser vendor prefix
function getBrowserPrefix() {
  for (var i = 0; i < browserPrefixes.length; i++) {
    if(getHiddenPropertyName(browserPrefixes[i]) in document) {
      // return vendor prefix
      return browserPrefixes[i];
    }
  }

  // no vendor prefix needed
  return null;
}

// bind and handle events
var browserPrefix = getBrowserPrefix(),
    hiddenPropertyName = getHiddenPropertyName(browserPrefix),
    visibilityEventName = getVisibilityEvent(browserPrefix);

function onVisible() {
  // prevent double execution
  if(isVisible) {
    return;
  }

  // change flag value
  isVisible = true;
  console.log('visible}

function onHidden() {
  // prevent double execution
  if(!isVisible) {
    return;
  }

  // change flag value
  isVisible = false;
  console.log('hidden}

function handleVisibilityChange(forcedFlag) {
  // forcedFlag is a boolean when this event handler is triggered by a
  // focus or blur eventotherwise it's an Event object
  if(typeof forcedFlag === "boolean") {
    if(forcedFlag) {
      return onVisible();
    }

    return onHidden();
  }

  if(document[hiddenPropertyName]) {
    return onHidden();
  }

  return onVisible();
}

document.addEventListener(visibilityEventName, handleVisibilityChange, false);

// extra event listeners for better behaviour
document.addEventListener('focus', function() {
  handleVisibilityChange(true);
}, false);

document.addEventListener('blur', function() {
  handleVisibilityChange(false);
}, false);

window.addEventListener('focus', function() {
    handleVisibilityChange(true);
}, false);

window.addEventListener('blur', function() {
  handleVisibilityChange(false);
}, false);

Je me réjouis de tout commentaire sur cette solution de contournement. Quelques autres grandes sources d'idées sur ce sujet:

Utilisation de l'API de visibilité de page Utilisation plus efficace du matériel PC en HTML5: nouvelles API de performances Web, partie 2 Introduction à l'API de visibilité de page Conclusion Les technologies du Web évoluent continuellement, nous nous remettons toujours d'un passé sombre où les tables où le balisage king, où la sémantique n'avait pas d'importance, et il n'y avait pas de normes sur la façon dont un navigateur devrait afficher une page.

Il est important que nous poussions ces nouvelles normes vers l'avant, mais parfois nos exigences de développement nous obligent à nous adapter à ce type de transitions, en gérant les préfixes des fournisseurs, en testant dans différents navigateurs et différents systèmes d'exploitation ou en dépendant d'outils tiers pour identifier correctement ces différences. .

Nous ne pouvons qu'espérer un avenir où les spécifications du W3C seront strictement révisées, strictement mises en œuvre par les équipes de développeurs de navigateurs, et peut-être qu'un jour nous aurons une norme commune pour nous tous.

En ce qui concerne l'API de visibilité des pages, citons simplement George Berkeley et disons que:

"Être visible" est perçu.

13
agbb

Une solution de travail est proposée décrite ici: https://stackoverflow.com/a/9502074/698168 . Il utilise une combinaison de l'API de visibilité de page du W3C, de flou/focus et de mouvements de souris. Les pages HTML cachées liées à Alt + Tab sont identifiées de manière probabiliste (c'est-à-dire que vous ne pouvez pas déterminer si votre page est masquée avec une précision de 100%).

2
Julien Kronegg

nous pouvons faire comme ci-dessous lors du basculement entre les onglets et le basculement entre les applications

 var pageVisible = true;  
 function handleVisibilityChange() {
      if (document.hidden) {
        pageVisible = false;
      } else  {
        pageVisible = true;
      }
      console.log("handleVisibilityChange")
      console.log("pageVisible", pageVisible)
      // some function call
    }
    document.addEventListener("visibilitychange", handleVisibilityChange, false);
    window.addEventListener('focus', function() {
        pageVisible = true;
        // some function call 
    }, false);
    window.addEventListener('blur', function() {
      pageVisible = false;
      // some function call  
    }, false);
1

Il y a une solution très simple à cela que j'ai trouvée.

Vous avez juste besoin de passer false à useCapture tout en attachant un écouteur d'événements au document. Fonctionne comme un charme!

 document.addEventListener('visibilitychange', function () {
  // code goes here
}, false)
0
vishal kokate