web-dev-qa-db-ja.com

Altキーを押しながらTabキーを押してプログラムまたはウィンドウを切り替えるか、タスクバーをクリックしても、visibilitychangeイベントがトリガーされない

問題は、イベント「visibilitychange」の動作にあります。

トリガーされます:-ブラウザウィンドウ内の別のタブに切り替えたとき。

  • ブラウザウィンドウの最小化/復元ボタンをクリックすると、.

(これは問題ありません)

トリガーされません:-Alt + Tabを使用して別のウィンドウ/プログラムに切り替えたとき。

  • タスクバーをクリックして別のウィンドウ/プログラムに切り替えたとき。

(これはトリガーする必要があります。最小化時と同じように、ウィンドウの可視性が変わる可能性があるためです)


W3ページ可視性APIドキュメントhttp://www.w3.org/TR/page-visibility/

に関する「ページの可視性」の定義はありません ALT+TAB/スペックシートのプログラムの切り替え。 OSとブラウザの間に何か関係があると思います。


テスト済み

  • ブラウザ:Chrome 40.0.2214.115 m/Firefox 36.0.1/Internet Explorer 11.0.9600.17107
  • [〜#〜] os [〜#〜]:Windows 8.1

この動作を修正する回避策はありますか?実装は非常に単純です。jQueryを使用して「visibilitychange」イベントをリッスンし、そのコールバックで「document.visibilityState」の値を確認しますが、問題は予期したときにイベントが発生しないことです。

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

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

これはjQueryがなくても実行できますが、 ALT+TAB タスクバースイッチの非表示/表示の期待される動作がまだありません:

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

Ifvisible.jsモジュール( https://github.com/serkanyersen/ifvisible.js )も試しましたが、動作は同じです。

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

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

他のブラウザではテストしていません。WindowsでChrome=)で動作しない場合、他のブラウザはまだ気にしていません。

ヘルプや提案はありますか?


更新

イベント名に別のベンダープレフィックス(visibilitychange、webkitvisibilitychange、mozvisibilitychange、msvisibilitychange)を使用してみましたが、タスクバーで別のプログラムに切り替えてもイベントがトリガーされません。 ALT+TAB、またはウィンドウ全体でスタートメニューウィンドウをウィンドウキーで開いた場合でも、画面全体が覆われます。

Chrome、Firefox、Internet Explorerでもまったく同じ問題を再現できます。

アップデート#2

こちら この問題について私が書いたまとめと、発生した問題を解決するための純粋なJavascriptの回避策。

アップデート#3

ソースのブログ投稿のコピーが含まれるように編集されました。 (受け入れられた回答を参照)

27
agbb

こちら この問題について私が書いたまとめと、発生した問題を解決するための純粋なJavaScriptでの回避策。

ソースのブログ投稿のコピーを含めるように編集されました:


私たちが開発するあらゆる種類のjavascriptアプリケーションでは、現在のユーザーの可視状態に応じて反応する機能やアプリケーションの変更がある可能性があります。これは、ユーザーがALT + TABを押して別のウィンドウに移動し、統計を追跡するときに、ビデオの再生を一時停止することです。ユーザーがアプリケーションを操作する方法、ユーザーが別のタブに切り替える頻度、ユーザーが戻るまでにかかる時間、およびこの種のAPIの恩恵を受けることができる多くのパフォーマンス改善について。

Page Visibility APIは、document.hidden(ブール値)とdocument.visibilityState(「hidden」、「visible」、「prerender」、「unloaded」のいずれかの文字列である可能性があります)の2つの最上位属性を提供します。これは、私たちがリッスンできるイベントなしでは十分ではありません。そのため、APIは便利な可視性変更イベントも提供しています。

そこで、可視性の変化に対応するための基本的な例を以下に示します。

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

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

Document.visibilityState値を確認することもできます。

ベンダーの問題に対処するJohn SmibertによるGeorge Berkeley

一部のブラウザーの実装の一部では、属性またはイベント名にベンダープレフィックスを付ける必要があります。つまり、msvisibilitychangeイベントをリッスンするか、document.webkitHidden属性またはdocument.mozHidden属性を確認する必要がある場合があります。これを行うには、ベンダープレフィックス付きの属性が設定されているかどうかを確認する必要があります。現在のブラウザで使用されている属性がわかったら(プレフィックスが必要な場合のみ)、イベントと属性に名前を付けることができます。正しく。

これらの接頭辞を処理する方法に関するアプローチの例を次に示します。

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

その他の問題「ページの可視性」の定義には難しい問題があります。別のウィンドウでウィンドウフォーカスが失われた場合に、アプリケーションが表示されているかどうかを確認する方法はありますが、画面上の実際の可視性は確認できません。 ALT + TAB、WIN/MACキー(スタートメニュー/ダッシュ)、タスクバー/ドックアクション、WIN + L(画面のロック)、ウィンドウの最小化、ウィンドウのクローズ、タブの切り替えなど、失われたさまざまな種類の可視性についてはどうでしょうか。モバイルデバイスでの動作はどうですか?

可視性が失われたり、取得されたりする可能性のある方法は数多くあり、ブラウザとOSの間で起こり得る多くのやり取りがあるため、W3C仕様に適切で完全な「可視ページ」の定義はないと思います。これは、document.hidden属性に対して取得する定義です。

HIDDEN ATTRIBUTE取得時に、最上位のブラウジングコンテキスト(ブラウザのビューポートのルートウィンドウ)[HTML5]に含まれるドキュメントがまったく表示されない場合、hidden属性はtrueを返す必要があります。最上位のブラウジングコンテキストに含まれるドキュメントが少なくとも1つの画面で少なくとも部分的に表示される場合、属性はfalseを返す必要があります。

DocumentのdefaultViewがnullの場合、取得時に、hidden属性はtrueを返す必要があります。

通常はフルスクリーンでありながらページのビューを表示するユーザー補助ツールに対応するために、該当する場合、ユーザーエージェントが最小化されていないが他のアプリケーションによって完全に隠されている場合、この属性はfalseを返す場合があります。

たとえば、イベントが実際に発生したときにいくつかの不整合が見つかりました。たとえば(Windows 8.1ではChrome 41.0.2272.101 m)Altキーを押しながらTabキーを押して別のウィンドウまたはプログラムに移動しても、もう一度Altキーを押しながらTabキーを押すと、イベントは発生しません。戻るにはIS CTRL + TABを押してからCTRL + SHIFT + TABを押すとブラウザのタブが切り替わります。最小化ボタンをクリックしても起動されますが、ウィンドウが最大化されておらず、ブラウザーウィンドウの動作をしているエディターウィンドウをクリックしたため、このAPIの動作とさまざまな実装はまだ不明です。

これの回避策は、より適切に実装されたフォーカスイベントとブラーイベントを利用して補正し、複数の実行を防ぐために内部フラグを使用して「ページの可視性」の問題全体にカスタムアプローチを作成することです。これが私が思いついたものです。 :

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

この回避策に関するフィードバックをお待ちしています。この主題に関するアイデアのいくつかの他の素晴らしい情報源:

ページ可視性APIの使用HTML5でのPCハードウェアのより効率的な使用:新しいWebパフォーマンスAPI、パート2ページ可視性APIの概要結論Webのテクノロジーは継続的に進化しており、マークアップのあるテーブルの暗い過去からまだ回復しています王、意味論は重要ではなく、ブラウザがページをレンダリングする方法に関する標準ではありませんでした。

これらの新しい標準を前進させることが重要ですが、開発の要件により、ベンダーのプレフィックスを処理したり、さまざまなブラウザーやOSでテストしたり、サードパーティのツールに依存してこの違いを適切に特定したりすることで、このような移行に対応する必要が生じる場合があります。

W3C仕様が厳密に改訂され、ブラウザ開発者チームによって厳密に実装される未来が望めます。おそらく、いつか私たち全員が作業するための共通の標準が用意されるでしょう。

Page Visibility APIについては、ちょっとジョージバークレーを引用して、次のように言ってみましょう。

「見えること」が知覚されている。

13
agbb

ここで説明されている実用的なソリューションが提案されています: https://stackoverflow.com/a/9502074/698168 。 W3C Page Visibility API、ぼかし/フォーカス、マウスの動きを組み合わせて使用​​します。 Alt + Tabに関連する非表示のHTMLページは、確率的な方法で識別されます(つまり、ページが100%の精度で非表示になっているかどうかを判断できません)。

2
Julien Kronegg

タブを切り替えたり、アプリケーションを切り替えたりすると、以下のようになります

 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

私が遭遇したこれに対する非常に簡単な解決策があります。

ドキュメントにイベントリスナーをアタッチするときに、useCaptureにfalseを渡すだけです。魅力的な作品!

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