ブラウザウィンドウが現在アクティブでないかどうかを検出する方法はありますか?


585

JavaScriptを定期的に使用している。ユーザーがサイトを見ていない場合(つまり、ウィンドウまたはタブにフォーカスがない場合)は、実行しない方がいいでしょう。

JavaScriptを使用してこれを行う方法はありますか?

私の参照点:使用しているウィンドウがアクティブでない場合、Gmailチャットは音を鳴らします。


8
以下の回答に満足できない場合は、requestAnimationFrameAPIを確認するか、ウィンドウが表示されていないときにsetTimeout/ の頻度をsetInterval下げる最新機能を使用してください(たとえば、Chromeでは1秒)。
Rob W

2
document.body.onblur = function(e){console.log( 'lama');}は、非フォーカス要素に対して機能しました。
WhyMe

2
参照してください、この答えに戻って落下、W3Cページの可視性APIを使用してクロスブラウザの互換性ソリューションのためにblur/ focusそれをサポートしていないブラウザで。
Mathias Bynens 2013

2
以下の回答の80%はこの質問に対する回答ではありません。質問は現在アクティブではないことを尋ねますが、以下のトンの答えは目に見えないことについてであり、これはこの質問に対する答えではありません。彼らは間違いなく「ない答え」としてフラグ付けされなければならない
gman

回答:


691

最初にこの回答を書いて以来、W3Cのおかげで新しい仕様が推奨ステータスに達しました。ページの可視性API(上のMDNは)今のページがユーザーに隠されているとき、私たちは、より正確に検出することができます。

document.addEventListener("visibilitychange", onchange);

現在のブラウザーサポート:

  • Chrome 13以降
  • Internet Explorer 10以降
  • Firefox 10以降
  • Opera 12.10以降 [ ノートを読む ]

次のコードは、互換性のないブラウザーでの信頼性の低いぼかし/フォーカスメソッドにフォールバックします。

(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そして、onfocusoutされているIE 9のために必要と下げて他のすべてのを利用している間、onfocusおよびonbluriOSの、用途を除いて、onpageshowそしてonpagehide


1
@bellpeace:IEはiframeから上部ウィンドウに伝播する必要がfocusinありfocusoutます。新しいブラウザーの場合は、各iframeのオブジェクトのfocusおよびblurイベントを処理するだけで済みwindowます。私が追加したばかりの更新されたコードを使用する必要があります。これにより、少なくとも新しいブラウザーでこれらのケースがカバーされます。
アンディE

3
@JulienKronegg:そのため、私の回答では、最初に回答を書いた後にワーキングドラフトステータスに入ったPage Visibility APIについて具体的に言及しています。focus / blurメソッドは、古いブラウザに限られた機能を提供します。あなたの答えのように、他のイベントへのバインドはこれより多くをカバーせず、動作の違いのリスクがより高くなります(カーソルの下にウィンドウがポップアップしたときにIEがマウスアウトを起動しないなど)。より適切なアクションは、ページが非アクティブであるために更新の頻度が少ないことをユーザーに示すメッセージまたはアイコンを表示することです。
アンディE

6
@AndyE私はクロムでこの解決策を試しました。タブを変更すると機能しますが、ウィンドウ(ALT + Tab)を変更すると機能しません。よろしいですか?ここにフィドルがあります-jsfiddle.net/8a9N6/17
トニーランパダ

2
@Heliodor:とりあえず、解答のコードは最小限にしたいと思います。実装者がボディにクラスを設定することを避け、完全に異なるアクション(タイマーの停止と開始など)を実行したい場合があるため、これはカットアンドペーストの完全なソリューションを意図したものではありません。
アンディE

8
@AndyEこのソリューションは、ユーザーがタブを変更した場合、またはウィンドウを最小化/最大化した場合にのみ機能するようです。ただし、ユーザーがタブをアクティブのままにした場合、onchangeイベントはトリガーされませんが、タスクバーからタブを介して別のプログラムを最大化します。そのシナリオの解決策はありますか?ありがとう!
user1491636 14年

132

あなたがしなければならないのはこれだけなので、私はjQueryを使用します:

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

または少なくともそれは私のために働いた。


1
私にとって、これはiframeで2回呼び出します
msangel 2013年

Firefoxでは、Firebugコンソール内(同じページ上)をクリックするwindowとフォーカスが失われますが、これは正しいことですが、意図によっては、必要とするものとは異なる場合があります。
Majid Fouladpour 2013年

21
これは現在のバージョンの最新のブラウザーでは機能しません。承認済みの回答(Page Visibility API)を参照してください
Jon z

このソリューションはiPadでは機能しません "pageshow"イベントを使用してください
ElizaS

ページが読み込まれると、BLURとFOCUSの両方が起動します。ページから新しいウィンドウを開いても何も起こりませんが、新しいウィンドウが閉じると両方のイベントが発生します:/(IE8を使用)
SearchForKnowledge

49

ユーザーがHTMLページを表示できるかどうかを判断するために使用される典型的な方法は3つありますが、どれも完全には機能しません。

  • W3Cページの可視性のAPIは(:Firefoxの10、MSIE 10、クロム13からサポート)これを行うことになっています。ただし、このAPIがイベントを発生させるのは、ブラウザのタブが完全にオーバーライドされたとき(たとえば、ユーザーが1つのタブから別のタブに変更したとき)だけです。可視性を100%の精度で決定できない場合、APIはイベントを発生させません(たとえば、Alt + Tabで別のアプリケーションに切り替えます)。

  • 使用してフォーカス/ぼかしベースの方法は、あなたの偽陽性の多くを提供します。たとえば、ユーザーがブラウザーウィンドウの上に小さいウィンドウを表示すると、ブラウザーウィンドウはフォーカスを失います(onblur上げられます)が、ユーザーはそれを見ることができます(したがって、更新する必要があります)。http://javascript.info/tutorial/focusも参照してください

  • ユーザーアクティビティ(マウスの移動、クリック、キー入力)に依存していると、多くの誤検知が発生します。上記と同じケース、またはユーザーがビデオを見ていると考えてください。

上記の不完全な動作を改善するために、3つのメソッドの組み合わせを使用します。W3CVisibility API、次にフォーカス/ぼかし、ユーザーアクティビティメソッドを使用して、誤検知率を減らします。これにより、次のイベントを管理できます。

  • ブラウザータブを別のタブに変更する(W3C Page Visibility APIのおかげで100%の精度)
  • Alt + Tabなどにより、ページが別のウィンドウに隠れている可能性があります(確率的= 100%正確ではありません)
  • ユーザーの注意がHTMLページに集中していない可能性があります(確率的= 100%正確ではありません)

これがどのように機能するかです。ドキュメントがフォーカスを失うと、ウィンドウが表示されているかどうかを判断するために、ドキュメントでのユーザーアクティビティ(マウスの移動など)が監視されます。ページの可視性の確率は、ページでの最後のユーザーアクティビティの時間に反比例します。ユーザーがドキュメントで長時間アクティビティを行わない場合、ページはおそらく表示されません。以下のコードは、W3C Page Visibility APIを模倣しています。同じように動作しますが、誤検知率はわずかです。マルチブラウザであるという利点があります(Firefox 5、Firefox 10、MSIE 9、MSIE 7、Safari 5、Chrome 9でテスト済み)。

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

    <スクリプト>
    / **
    指定されたオブジェクトのイベントにハンドラーを登録します。
    @param objイベントを発生させるオブジェクト
    @param evTypeイベントタイプ:クリック、キープレス、マウスオーバー、...
    @param fnイベントハンドラー関数
    @param isCapturingイベントモードを設定します(true =イベントのキャプチャ、false =バブリングイベント)
    @returnイベントハンドラが正しくアタッチされている場合はtrue
    * /
    function addEvent(obj、evType、fn、isCapturing){
      if(isCapturing == null)isCapturing = false; 
      if(obj.addEventListener){
        // Firefox
        obj.addEventListener(evType、fn、isCapturing);
        trueを返します。
      } else if(obj.attachEvent){
        // MSIE
        var r = obj.attachEvent( 'on' + evType、fn);
        rを返す;
      } そうしないと {
        falseを返します。
      }
    }

    //潜在的なページの可視性の変更に登録します
    addEvent(document、 "potentialvisilitychange"、function(event){
      document.getElementById( "x")。innerHTML + = "potentialVisilityChange:potentialHidden =" + document.potentialHidden + "、document.potentiallyHiddenSince =" + document.potentiallyHiddenSince + "s <br>";
    });

    // W3C Page Visibility 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.hidden!== "hidden"){
      hidden = "非表示";
      visibilityChange = "visibilitychange";
    }
    if(hidden!= null && visibilityChange!= null){
      addEvent(document、visibilityChange、function(event){
        document.getElementById( "x")。innerHTML + = visibilityChange + ":" + hidden + "=" + document [hidden] + "<br>";
      });
    }


    var potentialPageVisibility = {
      pageVisibilityChangeThreshold:3 * 3600、//秒単位
      init:function(){
        function setAsNotHidden(){
          var dispatchEventRequired = document.potentialHidden;
          document.potentialHidden = false;
          document.potentiallyHiddenSince = 0;
          if(dispatchEventRequired)dispatchPageVisibilityChangeEvent();
        }

        function initPotentiallyHiddenDetection(){
          if(!hasFocusLocal){
            //ウィンドウにフォーカスがない=>ウィンドウ内のユーザーアクティビティを確認する
            lastActionDate = new Date();
            if(timeoutHandler!= null){
              clearTimeout(timeoutHandler);
            }
            timeoutHandler = setTimeout(checkPageVisibility、potentialPageVisibility.pageVisibilityChangeThreshold * 1000 + 100); // Firefoxでの丸めの問題を回避するために+100 ms
          }
        }

        function dispatchPageVisibilityChangeEvent(){
          UnifiedVisilityChangeEventDispatchAllowed = false;
          var evt = document.createEvent( "Event");
          evt.initEvent( "potentialvisilitychange"、true、true);
          document.dispatchEvent(evt);
        }

        function checkPageVisibility(){
          var potentialHiddenDuration =(hasFocusLocal || lastActionDate == null?0:Math.floor((new Date()。getTime()-lastActionDate.getTime())/ 1000));
                                        document.potentiallyHiddenSince = potentialHiddenDuration;
          if(potentialHiddenDuration> = potentialPageVisibility.pageVisibilityChangeThreshold &&!document.potentialHidden){
            //ページの可視性の変更のしきい値が急上昇=>偶数を上げる
            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:<br>";
        });
        addEvent(document、 "pagehide"、function(event){
          document.getElementById( "x")。innerHTML + = "pagehide / doc:<br>";
        });
        addEvent(window、 "pageshow"、function(event){
          document.getElementById( "x")。innerHTML + = "pageshow / win:<br>"; //ページが最初に表示されたときに発生します
        });
        addEvent(window、 "pagehide"、function(event){
          document.getElementById( "x")。innerHTML + = "pagehide / win:<br>"; //発生していません
        });
        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(window、 "blur"、function(event){
          hasFocusLocal = false;
          initPotentiallyHiddenDetection();
        });
        addEvent(window、 "focus"、function(event){
          hasFocusLocal = true;
          setAsNotHidden();
        });
        setAsNotHidden();
      }
    }

    potentialPageVisibility.pageVisibilityChangeThreshold = 4; //テストには4秒
    potentialPageVisibility.init();
    </ script>

現在、誤検知のないクロスブラウザーソリューションは機能していないため、Webサイトでの定期的なアクティビティを無効にすることを2度考えるべきです。


undefinedキーワードの代わりに文字列 'undefined'で厳密な比較演算子を使用すると、上記のコードで誤検知が発生しませんか?
Jonathon

@kiran:実際にはAlt + Tabで動作しています。小さなウィンドウに切り替えてページが完全に非表示になることを保証できないため、Alt + Tabを実行してもページが非表示であるかどうかを判断できません。これが「潜在的に非表示」の概念を使用する理由です(この例では、しきい値は4秒に設定されているため、Alt + Tabを使用して少なくとも4秒間別のウィンドウに切り替える必要があります)。しかし、あなたのコメントは答えがはっきりしていないことを示しているので、私はそれを言い換えました。
Julien Kronegg、2016

@JulienKronegg私はこれがまだ最高の解決策だと思います。ただし、上記のコードは非常にいくつかのリファクタリングと抽象化を必要とします。それをGitHubにアップロードして、コミュニティにリファクタリングさせてみませんか?
Jacob

1
@ジェイコブ私はあなたが私の解決策を気に入ってうれしいです。ご自分でGitHubプロジェクトに自由に宣伝してください。私は、クリエイティブコモンズBY creativecommons.org/licenses/by/4.0
Julien Kronegg

26

GitHubには、きちんとしたライブラリがあります。

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

例:

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

私が持っているすべてのブラウザーでバージョン1.0.1をテストしましたが、次のバージョンで動作することを確認できます。

  • IE9、IE10
  • FF 26.0
  • Chrome 34.0

...そしておそらくすべての新しいバージョン。

以下とは完全に連携しません:

  • IE8-タブ/ウィンドウが現在アクティブであることを常に示します(.now()常にtrue私に戻ります)

受け入れられた回答はIE9で問題を引き起こしました。このライブラリはうまく機能します。
トムテマン2015年

20

使用: ページ可視性API

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

使ってもいいですか ? http://caniuse.com/#feat=pagevisibility


問題はページの可視性についてではありません。それはアクティブ/アクティブではない
gman

OPは
IDE

1
私はideについても話していません。別のアプリへのalt-tabbing / cmd-tabbingについて話している。突然ページがアクティブでなくなりました。ページ可視化APIは、ページがアクティブでないかどうかを知るのに役立ちません。ページが非表示になっているかどうかを知るのに役立ちます。
gman 2018

18

アプリのCometチャットを作成し、別のユーザーからメッセージを受け取ったときに使用します。

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

2
IE6をサポートする最もクリーンなソリューション
Paul Cooper

4
document.hasFocus()それを行うための最もクリーンな方法です。可視性APIまたはイベントベースを使用する他のすべての方法、またはさまざまなレベルのユーザーアクティビティ/アクティビティの欠如を探すことは、非常に複雑になり、エッジケースや穴でいっぱいになります。単純な間隔に配置し、結果が変化したときにカスタムイベントを発生させます。例:jsfiddle.net/59utucz6/1
danatcofo

1
効率的で、他のソリューションとは異なり、別のブラウザーのタブまたはウィンドウ、さらには別のアプリケーションに切り替えたときに正しいフィードバックを提供します。
ow3n 2017


1
Chrome Devツールを開くと、document.hasFocus()はfalseになります。または、ブラウザの上部パネルをクリックしても、同じことが起こります。このソリューションがビデオ、アニメーションなどを一時停止するのに適しているかどうかは
わかり

16

私はコミュニティのwiki回答を使い始めましたが、Chromeでalt-tabイベントを検出していないことに気付きました。これは、使用可能な最初のイベントソースを使用するためです。この場合、ChromeではAltタブを追跡しないように見えるページ可視性APIです。

ページフォーカスが変更される可能性のあるすべてのイベントを追跡するために、スクリプトを少し変更することにしました。ドロップインできる関数は次のとおりです。

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

次のように使用します。

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

このバージョンは、すべての異なる可視性イベントをリッスンし、それらのいずれかが変更を引き起こした場合にコールバックを起動します。focusedそしてunfocusedハンドラは、複数のAPIが、同じ可視性の変化をキャッチした場合、コールバックが複数回呼び出されていないことを確認してください。


たとえばChromeにはとの両方がdocument.hiddenありdocument.webkitHiddenます。せずelseif建設我々は2つのコールバックコールが右になるだろうか?
Christiaan Westerbeek

@ChristiaanWesterbeekそれは良い点です、私はそれについて考えていませんでした!この投稿を編集できる場合は、同意してください:)
Daniel Buckmaster

ちょっとちょっと待ってください。ChristiaanWesterbeekによって提案され、実際には@ 1.21Gigawattsによって追加された「else」を追加する編集は、良い考えのようには思えません。Danielの当初の購入を無効にします。並列メソッド。また、何も変化しない場合、focused()およびunfocused()が余分な呼び出しを抑制するため、コールバックが2回呼び出されるリスクはありません。本当に最初のリビジョンに戻す必要があるようです。
Louis Semprini

@LouisSempriniは素晴らしいキャッチです。コードの本来の意図を忘れていました!オリジナルを復元し、説明を追加しました!
Daniel Buckmaster

今日の時点でこれをチェックすると、少なくともChrome 78 + macosではalt + tabは検出されません
Hugo Gresse

7

これは本当にトリッキーです。以下の要件を満たしている場合、解決策はないようです。

  • このページには、ユーザーが制御できないiframeが含まれています
  • TABの変更(Ctrl + Tab)またはウィンドウの変更(Alt + Tab)によってトリガーされた変更に関係なく、表示状態の変更を追跡したい

これは次の理由で発生します:

  • ページのVisibility APIは、タブの変更を確実に通知できます(iframeを使用している場合でも)が、ユーザーがウィンドウを変更したことは通知できません。
  • ウィンドウのぼかし/フォーカスイベントをリッスンすると、iframeにフォーカスがない限り、alt + tabとctrl + tabを検出できます。

これらの制限が与えられた場合、以下を組み合わせたソリューションを実装することが可能です-ページ可視性API-ウィンドウぼかし/フォーカス-document.activeElement

次のことが可能です。

  • 1)親ページにフォーカスがある場合のctrl + tab:はい
  • 2)iframeにフォーカスがある場合のctrl + tab:はい
  • 3)親ページにフォーカスがある場合のalt + tab:はい
  • 4)iframeにフォーカスがあるときのalt + tab:いいえ <-残念

iframeにフォーカスがある場合、ぼかし/フォーカスイベントはまったく呼び出されず、ページのVisibility APIはalt + tabでトリガーされません。

@AndyEのソリューションに基づいて構築し、この(ほぼ良い)ソリューションをここに実装しました:https : //dl.dropboxusercontent.com/u/2683925/estante-components/visibility_test1.html(申し訳ありませんが、JSFiddleで問題が発生しました)。

これはGithubでも入手できます:https : //github.com/qmagico/estante-components

これはクロム/クロムで動作します。iframeのコンテンツを読み込まないことを除いて、Firefoxで動作します(理由は何か?)

とにかく、最後の問題(4)を解決する唯一の方法は、iframeでぼかし/フォーカスイベントをリッスンすることです。iframeをある程度制御できる場合は、postMessage APIを使用してそれを行うことができます。

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

私はまだ十分なブラウザでこれをテストしていません。これが機能しない場所に関する詳細情報を見つけることができる場合は、下のコメントでお知らせください。


私のテストでは、IE9、IE10、AndroidのChromeでも動作しました。
TonyLâmpada2013

1
iPadが完全に異なるソリューションを必要とするようだ- stackoverflow.com/questions/4940657/...
トニーLâmpada

3
これらのリンクはすべて404です。(
Daniel Buckmaster

6
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

これは、chrome 67、firefox 67、

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

3

あなたは使うことができます:

(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

HTML 5では、次のものも使用できます。

  • onpageshow:ウィンドウが表示されたときに実行されるスクリプト
  • onpagehide:ウィンドウが非表示のときに実行されるスクリプト

見る:


2
これはBFCacheに関連していると思います。ユーザーが[戻る]または[次へ]をクリックすると、コンピューターのデスクトップの上部にあるページには関連しません。
非極性

2

これは、Andy Eからの回答を改変したものです。

これにより、30秒ごとにページを更新するなどのタスクが実行されますが、ページが表示されてフォーカスされている場合のみです。

可視性が検出できない場合は、フォーカスのみが使用されます。

ユーザーがページにフォーカスすると、すぐに更新されます

ページはajax呼び出しの30秒後まで更新されません

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

フォーカス/ぼかし方法がない仕事(それはあなたの偽陽性の多くを提供します)に頼って、stackoverflow.com/a/9502074/698168を参照してください
ジュリアンKronegg

2

jQueryを使用しないソリューションについては、3つのページの状態に関する情報を提供するVisibility.jsを確認してください。

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

また、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();
});

古いブラウザ(IE <10; iOS <7)のフォールバックも利用可能です


ブラウザのサポートはどうですか?とりあえず、Chrome、Safari、Firefoxをうまくフォークします。
Selva Ganapathi

1

もう少し複雑な方法は、を使用setInterval()してマウスの位置をチェックし、最後のチェックと比較することです。マウスが一定時間動かされなかった場合、ユーザーはおそらくアイドル状態です。

これには、ウィンドウがアクティブでないかどうかを確認するだけでなく、ユーザーがアイドル状態かどうかを通知するという利点もあります。

多くの人が指摘しているように、これはユーザーまたはブラウザーウィンドウがアイドル状態であるかどうかを確認するのに必ずしも良い方法ではありません。私は、アイドル状態をチェックする1つの可能な方法を提案しています。


30
ユーザーがマウスを持っていない限り。
user1686 2009年

@Annan:これはcodinghorror.com/blog/2007/03/…です。
サイボーグ

これは、ユーザーがビデオを見ている場合にもサイコロを再生しません
jamiew

onkeypressまたは他の同様のイベントを使用してタイマーをリセットし、マウス以外の問題を解決できます。それはまだユーザーのための仕事を積極的にビデオを見るためにページを見ていないでしょう。もちろん、など、イメージを勉強
joshuahedlund

1

angular.jsの場合、これは(承認された回答に基づく)ディレクティブであり、これによりコントローラーは可視性の変化に対応できます。

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

});

次の例のように使用できます<div react-on-window-focus="refresh()">refresh()は、スコープ内にあるすべてのコントローラーのスコープ内のスコープ関数です。


0

これが、確実で最新のソリューションです。(甘いものを短く👌🏽)

document.addEventListener("visibilitychange", () => {
  console.log( document.hasFocus() )
})

これにより、フォーカスやぼかしなどの可視性イベントが発生したときにトリガーするリスナーが設定されます。


0

あなたが行動する場合には、全体のブラウザブラー:として私が提案したイベントの火のブラウザ失うフォーカスなしならば、コメントしています。私のアイデアは、ループでカウントアップし、イベントが発生した場合にカウンターをリセットすることです。カウンターが制限に達した場合、他のページにlocation.hrefを実行します。これは、dev-toolsで作業している場合にも発生します。

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

これはFFでテストに成功したドラフトです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.