JavaScriptを定期的に使用している。ユーザーがサイトを見ていない場合(つまり、ウィンドウまたはタブにフォーカスがない場合)は、実行しない方がいいでしょう。
JavaScriptを使用してこれを行う方法はありますか?
私の参照点:使用しているウィンドウがアクティブでない場合、Gmailチャットは音を鳴らします。
JavaScriptを定期的に使用している。ユーザーがサイトを見ていない場合(つまり、ウィンドウまたはタブにフォーカスがない場合)は、実行しない方がいいでしょう。
JavaScriptを使用してこれを行う方法はありますか?
私の参照点:使用しているウィンドウがアクティブでない場合、Gmailチャットは音を鳴らします。
回答:
最初にこの回答を書いて以来、W3Cのおかげで新しい仕様が推奨ステータスに達しました。ページの可視性API(上のMDNは)今のページがユーザーに隠されているとき、私たちは、より正確に検出することができます。
document.addEventListener("visibilitychange", onchange);
現在のブラウザーサポート:
次のコードは、互換性のないブラウザーでの信頼性の低いぼかし/フォーカスメソッドにフォールバックします。
(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
およびonblur
iOSの、用途を除いて、onpageshow
そしてonpagehide
。
focusin
ありfocusout
ます。新しいブラウザーの場合は、各iframeのオブジェクトのfocus
およびblur
イベントを処理するだけで済みwindow
ます。私が追加したばかりの更新されたコードを使用する必要があります。これにより、少なくとも新しいブラウザーでこれらのケースがカバーされます。
あなたがしなければならないのはこれだけなので、私はjQueryを使用します:
$(window).blur(function(){
//your code here
});
$(window).focus(function(){
//your code
});
または少なくともそれは私のために働いた。
window
とフォーカスが失われますが、これは正しいことですが、意図によっては、必要とするものとは異なる場合があります。
ユーザーが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を模倣しています。同じように動作しますが、誤検知率はわずかです。マルチブラウザであるという利点があります(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度考えるべきです。
GitHubには、きちんとしたライブラリがあります。
https://github.com/serkanyersen/ifvisible.js
例:
// If page is visible right now
if( ifvisible.now() ){
// Display pop-up
openPopUp();
}
私が持っているすべてのブラウザーでバージョン1.0.1をテストしましたが、次のバージョンで動作することを確認できます。
...そしておそらくすべての新しいバージョン。
以下とは完全に連携しません:
.now()
常にtrue
私に戻ります)使用: ページ可視性API
document.addEventListener( 'visibilitychange' , function() {
if (document.hidden) {
console.log('bye');
} else {
console.log('well back');
}
}, false );
使ってもいいですか ? http://caniuse.com/#feat=pagevisibility
アプリのCometチャットを作成し、別のユーザーからメッセージを受け取ったときに使用します。
if(new_message){
if(!document.hasFocus()){
audio.play();
document.title="Have new messages";
}
else{
audio.stop();
document.title="Application Name";
}
}
document.hasFocus()
それを行うための最もクリーンな方法です。可視性APIまたはイベントベースを使用する他のすべての方法、またはさまざまなレベルのユーザーアクティビティ/アクティビティの欠如を探すことは、非常に複雑になり、エッジケースや穴でいっぱいになります。単純な間隔に配置し、結果が変化したときにカスタムイベントを発生させます。例:jsfiddle.net/59utucz6/1
私はコミュニティの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が、同じ可視性の変化をキャッチした場合、コールバックが複数回呼び出されていないことを確認してください。
document.hidden
ありdocument.webkitHidden
ます。せずelse
にif
建設我々は2つのコールバックコールが右になるだろうか?
これは本当にトリッキーです。以下の要件を満たしている場合、解決策はないようです。
これは次の理由で発生します:
これらの制限が与えられた場合、以下を組み合わせたソリューションを実装することが可能です-ページ可視性API-ウィンドウぼかし/フォーカス-document.activeElement
次のことが可能です。
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
私はまだ十分なブラウザでこれをテストしていません。これが機能しない場所に関する詳細情報を見つけることができる場合は、下のコメントでお知らせください。
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);
});
あなたは使うことができます:
(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);
})();
HTML 5では、次のものも使用できます。
onpageshow
:ウィンドウが表示されたときに実行されるスクリプトonpagehide
:ウィンドウが非表示のときに実行されるスクリプト見る:
これは、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);
}
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)のフォールバックも利用可能です
もう少し複雑な方法は、を使用setInterval()
してマウスの位置をチェックし、最後のチェックと比較することです。マウスが一定時間動かされなかった場合、ユーザーはおそらくアイドル状態です。
これには、ウィンドウがアクティブでないかどうかを確認するだけでなく、ユーザーがアイドル状態かどうかを通知するという利点もあります。
多くの人が指摘しているように、これはユーザーまたはブラウザーウィンドウがアイドル状態であるかどうかを確認するのに必ずしも良い方法ではありません。私は、アイドル状態をチェックする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()
は、スコープ内にあるすべてのコントローラーのスコープ内のスコープ関数です。
あなたが行動する場合には、全体のブラウザブラー:として私が提案したイベントの火のブラウザ失うフォーカスなしならば、コメントしています。私のアイデアは、ループでカウントアップし、イベントが発生した場合にカウンターをリセットすることです。カウンターが制限に達した場合、他のページに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でテストに成功したドラフトです。
requestAnimationFrame
APIを確認するか、ウィンドウが表示されていないときにsetTimeout
/ の頻度をsetInterval
下げる最新機能を使用してください(たとえば、Chromeでは1秒)。