ブラウザタブにフォーカスがあるかどうかを検出する


149

タブにフォーカスがあることを検出する信頼できるクロスブラウザーの方法はありますか?

このシナリオでは、株価を定期的にポーリングするアプリケーションがあり、ページにフォーカスがない場合、ポーリングを停止して、特に人々がさまざまなポートフォリオで複数のタブを開くことのファンである場合に、トラフィックノイズを節約できます。

であるwindow.onblurwindow.onfocus、このためのオプション?


回答:


127

はい、window.onfocusそしてwindow.onblur自分のシナリオのために働く必要があります。

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


3
これのonfocusin / onfocusoutの側面と、ユーザーに一時停止したことを伝えることに関するメモは、本当に良いメモです。ありがとう。
フェントン、2011

7
この方法では、ページの読み込み時にページがアクティブか非アクティブかを区別できないことに注意してください。
pimvdb 2011

@SteveFenton - onfocusあなたが言及したイベントはIE専用ですcrossbrowserが、これは良いノートとみなされるであろう、なぜ私は..あなたで見ることができない、である
VSYNC

1
@vsync-リンクされた記事を読むと、「onfocusin」と「onfocus」の両方が使用されていることがわかります。
フェントン2014年

少なくとも2つの違いを説明できますか?
Lenar Hoyt 2016

53

重要な編集:この回答は古くなっています。それを書いてから、Visibility API( mdn example spec)が導入されました。これは、この問題を解決するためのより良い方法です。


var focused = true;

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

私の知る限り、focusそしてblurすべてでサポートされています...すべて。(http://www.quirksmode.org/dom/events/index.htmlを参照


2
これらすべてのソリューションでは、JavaScriptが完全にロードされる前にユーザーがタブを変更するリスクを冒すことに注意してください。これにより、フォーカスされた値に誤った値が割り当てられます。それを回避する良い方法があるかどうかはわかりません。
JayD3e 2013

更新リンクはまさに​​私が探していたものです。追加してくれてありがとう!
webLacky3rdClass 2015

問題は、ページにフォーカスがあるかどうかを検出することです。これは、ページが表示されているかどうかを検出することとは異なります。複数のページを同時に(別のウィンドウで)表示できますが、フォーカスがあるのは1ページだけです。ニーズに合った手法を使用しますが、違いを知っています。
jaredjacobs 2018

1
これは、より大きなアプリケーションで他のイベントリスナーをオーバーライドするリスクがあるため、危険な解決策です。:あなたは、代わりにこの答え従ってくださいstackoverflow.com/a/21935031/549503
mmmeff

51

この問題について検索しているときに、Page Visibility APIを使用するよう推奨されています。最新のブラウザのほとんどは、このAPIをCan I Use:http : //caniuse.com/#feat=pagevisibilityに従ってサポートしています。

これが実際の例です(このスニペットから派生):

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

更新:上記の例では、GeckoとWebKitのブラウザーに接頭辞付きのプロパティがありましたが、これらのブラウザーはしばらくの間、接頭辞なしのPage Visibility APIを提供しているため、この実装を削除しました。IE10との互換性を保つために、Microsoft固有のプレフィックスを保持しました。


ベンダーの接頭辞がこれから出てきたら、おそらく切り替えます!
フェントン

正式なW3C勧告(2013年10月29日)があるため、これに関する実際の問題はベンダープレフィックスではありません。場合によっては、IE 10以降でページ表示APIがサポートされているという問題があります。IE9をサポートする必要がある場合は、別のアプローチを探す必要があります...
Ilija

これは、最新のすべてのブラウザでこれを行う正しい方法です。+1
Ajedi32

これらのベンダープレフィックスが本当に必要ですか?MDNとCanIUseによると、バージョン32以降のChromeやバージョン17以降のFirefoxではこれらは必要なく、IEでは必要ありませんでした。
Ajedi32 2015年

@ Ajedi32ありがとう。私はいくつかのテストと掘り下げを行って、それがまだ何に関連しているか、そして今は何が残されているかを確認する必要があります。
Ilija

37

誰も言及されていないのを見て驚いた document.hasFocus

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

MDNには詳細情報があります。


私のために動作します(ChromeとFirefoxでテスト済み)。受け入れ答え(ONFOCUS /のonblur)はなかったではない仕事
harmv

正解はまだ一番下にあります。StackOverflowへの道!
10月11

本当に、これは完璧な答えではありませんか?誰かが何か悪い面を見ていますか?
Gaspar

2
これの唯一の欠点は、タブがiframe内からフォーカスされているかどうかを判断しようとすると、親ページがまだフォーカスされていないときにiframeが読み込まれた場合に失敗することです。これもカバーするには、ページの可視性APIを使用する必要があります。
Ivan

29

はい、それらはあなたのために働くはずです。あなたがたまたま私が出会ったこれらのテクニックを悪用するこのリンクを思い出させてくれました。おもしろい


2
+1-これは非常に巧妙なトリックです。多くの人をだますことを想像できます。
フェントン2009

2
なんと独創的で不正な攻撃か。興味深いことを読んでくれてありがとう。
Voo

4

私はこのようにします(参照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
        }

    };  

この答えが@Ilijaによって与えられた答えとどのように異なるか説明できますか-違いはあるかもしれませんが、微妙です-ですから、それが何であり、なぜそれが違うべきなのかについての説明をいただければ幸いです。
Fenton

2

クロスブラウザjQueryソリューション! GitHubで未加工のまま利用可能

楽しくて使いやすい!

次のプラグインは、IE、Chrome、Firefox、Safariなどのさまざまなバージョンの標準テストを実行し、それに応じて宣言されたメソッドを確立します。また、次のような問題も扱います。

  • onblur | .blur / onfocus | .focus " duplicate "呼び出し
  • 単語などの代替アプリの選択によりウィンドウがフォーカスを失う
    • これは望ましくない傾向があります。銀行ページを開いている場合、onblurイベントがページをマスクするように指示し、電卓を開くとページが表示されなくなるからです。
  • ページの読み込み時にトリガーされない

使用方法は次のように簡単です。スニペットを実行」までスクロールします

$.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>


プラグイン用にコードを最小化しないでください。
Patrick Desjardins、

@PatrickDesjardinsええ。この週末を他のことと一緒に行うことを計画してください。私?私が持っているものの束の要点を作ります。githubのJdmckinstry。要旨に追加されると、これらのような古い回答へのリンクが追加されます
SpYk3HH

「Word」や「電卓」などの別のアプリに切り替えたときに、ページのフォーカスを失いたい場合はどうすればよいですか?
Benas

@Benasは間違っている可能性がありますが、私はそれが非常に基本的なの基本機能であると信じていjQuery(window).blur/focusます。このプラグインは、jQueryがまだ提供していない機能を提供することを目的としています
SpYk3HH
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.