web-dev-qa-db-ja.com

Javascript;同じ起源を持つタブ/ウィンドウ間の通信

ウィンドウAとウィンドウBの2つのウィンドウがあります。

  • ウィンドウAとウィンドウBは同じドメインを持っています
  • ウィンドウAとウィンドウBには親ウィンドウがありません。

質問:

  1. ウィンドウAがウィンドウBの参照を取得することは可能ですか?
  2. ウィンドウAにウィンドウBに何かを通知させる最もエレガントな方法は何ですか?
    (新しいHTML5仕様を含む)

私はこれを行うことを知っている2つの方法:

  • サーバーによるメッセージング:ウィンドウBがウィンドウAが何かを通知したかどうかを定期的にサーバーに尋ねる
  • ローカルデータによるメッセージング(HTML5):ウィンドウAがローカルデータを変更することを通知する場合、ウィンドウBは定期的にローカルデータの変更をチェックします。

しかし、2つの方法はそれほどエレガントではありません。
たとえば、ウィンドウBの参照を取得してwindow.postMessage()(HTML5)を使用すると良いでしょう

最終的な目標は、4つのFacebookタブを開いて1つのタブでチャットした場合、Facebookのようなものを作成することです。チャットはすべてのFacebookタブで最新になります。

68
brillout

私はlocalStorageを使用して質問で言及された共有ローカルデータソリューションに固執しています。これは、信頼性、パフォーマンス、およびブラウザーの互換性の点で最良のソリューションであると思われます。

localStorageは、すべての最新のブラウザーに実装されています。

storageイベントは、otherタブがlocalStorageに変更を加えると発生します。これは、通信の目的に非常に便利です。

参照はここにあります:
Webstorage
Webstorage-storage event

107
brillout

BroadcastChannel標準ではこれを行うことができます。現在、Firefoxに実装されており、Chrome(- caniusemdn ):

// tab 1
var ch = new BroadcastChannel('test');
ch.postMessage('some data');

// tab 2
var ch = new BroadcastChannel('test');
ch.addEventListener('message', function (e) {
    console.log('Message:', e.data);
});
23
Joel Richard

SharedWorkerは、タブ間で通信できる一般的なプロセスのWHATWG/HTML5仕様です。

12
rektide

あなたは言った:

最終的な目標は、4つのFacebookタブを開いて1つのタブでチャットすると、Facebookのようなものを作ることです。チャットはすべてのFacebookタブで実現されます。

これは、ビューのクロスビュー通信で設計するのではなく、チャットの更新をモデル(おそらくサーバー)に照会するデザインの副産物として発生するはずです。大量のデータの転送を扱っているのでなければ、なぜ心配するのですか?それは大きな利益なしで物事を複雑にするようです。

数年前、私がwindow.open既存のウィンドウの名前と空白のURLを使用して、既存のウィンドウへの参照を得ました(この動作は MDCに文書化されています および MSDNドキュメント =は、IE)でも機能することを示唆しています。しかし、それは何年も前のことであり、今日の世界でどれだけ普遍的にサポートされているかはわかりません。すべてのウィンドウに通信用の名前付きiframeが含まれ、サーバー側コードを介して一意の名前が付けられ、サーバー側コードによって他のウィンドウと通信されない限り、検索するウィンドウ名...ログインしたアカウントに関連する「現在の」ウィンドウ名をテーブルに保存し、そのアカウントにログインするように作成された新しいウィンドウにリストを与え、古い非アクティブなエントリをカリングします。古くなった場合、他の人を検索するときに新しいウィンドウを開くことになります...そして、ブラウザからブラウザへのサポートは不確かだと思います。)

4
T.J. Crowder

今後の SharedWorker に加えて、 クロスドキュメントメッセージング を使用することもできます。これははるかに広く supported です。このシナリオでは、window.openを使用して他のすべてのウィンドウを開くメインウィンドウが必要です。子ウィンドウは、window.openerpostMessage を使用できます。

フラッシュの使用がオプションである場合、フラッシュがインストールされたクライアントで仮想的にサポートされているはるかに古い LocalConnection もあります( サンプルコード )。

その他の代替方法:
古いブラウザーのwindow.location.hrefフォールバックを備えたjQueryのpostMessageプラグイン
非インスタント通信用のCookieベースのソリューション

4
zah

私の知る限り、ウィンドウが同じ親を持っていない場合、ウィンドウ間で通信することは不可能です。

両方が親ウィンドウから開かれている場合、親の変数参照を保持できるはずです。

親で、次のようにウィンドウを開きます。

childA = window.open(...);
childB = window.open(...)

childAで、次のようにchildBにアクセスします。

childB = window.opener.childA
1
Pekka 웃

私はそのようなトリックを行うきちんとした方法を持っていますが、制限があります:ドメインのポップアップを許可する必要があり、ウィンドウ間での通信を実装する1つのページを常に(タブまたはポップアップとして)開く必要があります。

例は次のとおりです。 http://test.gwpanel.org/test/page_one.html (ドメインのポップアップを有効にした後にページを更新します)

このトリックの主な機能-ポップアップは最後にURLフラグメント「#」で開かれます。これにより、ブラウザはウィンドウの場所を変更せず、すべてのデータを保存します。そして、window.postMessageが残りを行います。

0
Riki_tiki_tavi