Detectar se a guia do navegador tiver foco

Existe um modo confiável de navegação cruzada para detectar que uma guia tem foco.

O cenário é que temos um aplicativo que pesquisa regularmente os preços das ações e, se a página não tiver foco, poderíamos parar a votação e salvar a todos o ruído do tráfego, especialmente porque as pessoas são fãs de abrir várias guias com portfólios diferentes.

window.onblur e window.onfocus uma opção para isso?

Sim, window.onfocus e window.onblur devem funcionar para o seu cenário:

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

Importante Editar: Esta resposta está desatualizada. Desde que foi escrito, a API de visibilidade ( mdn , exemplo , especificação ) foi introduzida. É a melhor maneira de resolver este problema.


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

AFAIK, focus e blur são todos suportados em … tudo. (veja http://www.quirksmode.org/dom/events/index.html )

Ao pesquisar sobre esse problema, encontrei uma recomendação de que a API de visibilidade da página deveria ser usada. A maioria dos navegadores modernos oferece suporte a essa API de acordo com Can I Use: http://caniuse.com/#feat=pagevisibility .

Aqui está um exemplo de trabalho (derivado deste snippet ):

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

Atualização: O exemplo acima costumava ter propriedades prefixadas para os navegadores Gecko e WebKit, mas eu removi essa implementação porque esses navegadores oferecem API de visibilidade de página sem um prefixo por enquanto. Mantive o prefixo específico da Microsoft para permanecer compatível com o IE10.

Sim, esses devem funcionar para você. Você acabou de me lembrar deste link que eu descobri que explora essas técnicas. leitura interessante

Surpreendente ver ninguém mencionou document.hasFocus

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

O MDN tem mais informações.

Eu faria assim (Referência: 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 } }; 

Cruzeiro jQuery Solution! Raw disponível no GitHub

Divertido e fácil de usar!

O seguinte plugin passará pelo seu teste padrão para várias versões do IE, Chrome, Firefox, Safari, etc. e estabelecerá seus methods declarados de acordo. Também lida com questões como:

  • onblur | .blur / onfocus | .focus chamadas ” duplicadas
  • janela perdendo o foco através da seleção de aplicativo alternativo, como palavra
    • Isso tende a ser indesejável simplesmente porque, se você tem uma página de banco aberta, e o evento onblur diz para mascarar a página, então se você abrir a calculadora, você não poderá mais ver a página!
  • Não está sendo acionado no carregamento da página

Use é tão simples como: rolar para baixo para ” Run 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( $('').append( $('', { text: i }), $('', { 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; } 
  

See Console for Event Object Returned

Is Visible?

TRUE

Event Data { See Console for More Details }