web-dev-qa-db-fra.com

Javascript; communication entre onglets / fenêtres de même origine

J'ai deux fenêtres: la fenêtre A et la fenêtre B.

  • la fenêtre A et la fenêtre B ont le même domaine
  • la fenêtre A et la fenêtre B n'ont pas de fenêtre parent.

Des questions:

  1. Est-il possible pour la fenêtre A d'obtenir une référence de la fenêtre B?
  2. quelle est la façon la plus élégante de faire notifier quelque chose à la fenêtre B?
    (y compris les nouvelles spécifications HTML5)

Je suis conscient de cela de deux manières:

  • messagerie par serveur: où la fenêtre B demande régulièrement au serveur si la fenêtre A a notifié quelque chose
  • messagerie par données locales (HTML5): lorsque la fenêtre A souhaite notifier quelque chose, elle modifie les données locales, la fenêtre B vérifie régulièrement les données locales pour tout changement.

Mais les deux façons ne sont pas si élégantes.
Par exemple, il serait bien d'obtenir une référence de la fenêtre B et d'utiliser window.postMessage () (HTML5)

Le but ultime est de créer quelque chose comme Facebook où si vous ouvrez 4 onglets Facebook et discutez dans un onglet, le chat est à jour dans chaque onglet Facebook, ce qui est bien!

68
brillout

Je m'en tiens à la solution de données locales partagées mentionnée dans la question en utilisant localStorage. Il semble que ce soit la meilleure solution en termes de fiabilité, de performances et de compatibilité du navigateur.

localStorage est implémenté dans tous les navigateurs modernes.

L'événement storage se déclenche lorsque d'autres onglets modifient localStorage. C'est très pratique à des fins de communication.

Des références peuvent être trouvées ici:
Webstorage
Webstorage - événement de stockage

107
brillout

La norme BroadcastChannel permet de le faire. Pour l'instant, il est implémenté dans Firefox et Chrome ( caniuse , mdn ):

// 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 est la spécification WHATWG/HTML5 pour un processus commun qui peut communiquer entre les onglets.

12
rektide

Vous avez dit votre:

l'objectif ultime est de créer quelque chose comme Facebook où si vous ouvrez 4 onglets Facebook et discutez dans un onglet, le chat est actualisé sur chaque onglet Facebook, ce qui est bien!

Cela devrait se produire en tant que sous-produit de votre conception, les vues interrogeant le modèle (probablement le serveur) pour des mises à jour du chat, plutôt que d'avoir à concevoir dans la communication transversale. À moins que vous ayez à transférer d'énormes quantités de données, pourquoi vous en soucier? Il semble que cela compliquera les choses sans un gain énorme.

Il y a des années, j'ai découvert que si je le faisais window.open en utilisant le nom d'une fenêtre existante et une URL vide, j'ai obtenu une référence à la fenêtre existante (ce comportement est même documenté sur MDC et un commentaire sur les documents MSDN = suggère que cela fonctionne en IE également). Mais c'était il y a des années, je ne sais pas à quel point le support est universel dans le monde d'aujourd'hui, et bien sûr vous n'aurez pas de nom de la fenêtre à rechercher, sauf si toutes vos fenêtres incluent un iframe nommé pour la communication, nommé uniquement via le code côté serveur, puis communiqué aux autres fenêtres au moyen du code côté serveur ... (Pensée effrayante : Cela pourrait en fait être possible. Stockez les noms de fenêtre "actuels" liés à un compte connecté dans une table, donnez la liste à toute nouvelle fenêtre créée qui se connecte à ce compte, supprimez les anciennes entrées inactives. Mais si la liste est légèrement obsolète, vous ouvrirez de nouvelles fenêtres lorsque vous en rechercherez d'autres ... Et je parie que le support est incertain d'un navigateur à l'autre.)

4
T.J. Crowder

Outre le prochain SharedWorker , vous pouvez également utiliser messagerie croisée , qui est beaucoup plus largement pris en charge . Dans ce scénario, il doit y avoir une fenêtre principale chargée d'ouvrir toutes les autres fenêtres avec window.open. Les fenêtres enfants peuvent alors utiliser postMessage sur leur window.opener.

Si l'utilisation de flash est une option pour vous, il y a aussi le plus ancien LocalConnection virtuellement pris en charge sur tout client avec flash installé ( exemple de code ).

Autres méthodes de secours:
plugin postMessage pour jQuery avec fenêtre.location.href pour les anciens navigateurs
solution basée sur les cookies pour la communication non instantanée

4
zah

AFAIK, il est impossible de communiquer entre fenêtres si elles n'ont pas le même parent.

S'ils ont tous deux été ouverts à partir d'une fenêtre parent, vous devriez pouvoir obtenir les références de variable du parent.

Dans le parent, ouvrez les fenêtres comme ceci:

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

dans ChildA, accédez à childB comme ceci:

childB = window.opener.childA
1
Pekka 웃

J'ai une bonne façon de faire une telle astuce, mais avec des restrictions: vous devez autoriser les popups pour votre domaine et vous obtiendrez une page toujours ouverte (sous forme d'onglet ou de popup) qui mettra en œuvre les communications entre les fenêtres.

Voici un exemple: http://test.gwpanel.org/test/page_one.html (actualiser la page après avoir activé les popups pour le domaine)

La principale caractéristique de cette astuce - la fenêtre contextuelle est ouverte avec le fragment d'URL '#' à la fin, ce qui force le navigateur à ne pas changer l'emplacement de la fenêtre et à stocker toutes les données. Et window.postMessage fait le reste.

0
Riki_tiki_tavi