82

我有两个窗口:窗口 A 和窗口 B。

  • 窗口 A 和窗口 B 具有相同的域
  • 窗口 A 和窗口 B 没有任何父窗口。
  1. 窗口 A 是否有可能获得窗口 B 的引用?
  2. 让窗口 A 通知窗口 B 的最优雅的方法是什么?(包括新的 HTML5 规范)

我知道这样做的两种方法:

  • 服务器消息传递:窗口 B 定期询问服务器窗口 A 是否通知了某些内容
  • 通过本地数据发送消息 (HTML5):当窗口 A 想要通知某事它更改了本地数据时,窗口 B 会定期检查本地数据是否有任何更改。

但这两种方式都不是那么优雅。

例如,最好获取窗口 B 的引用并使用 window.postMessage() (HTML5)

最终目标是制作类似于 Facebook 的东西,如果您打开四个 Facebook 选项卡并在一个选项卡中聊天,则每个 Facebook 选项卡中的聊天都是最新的,这很整洁!

4

7 回答 7

131

我坚持使用问题中提到的共享本地数据解决方案localStorage。就可靠性、性能和浏览器兼容性而言,它似乎是最好的解决方案。

localStorage在所有现代浏览器中实现。

当其他选项卡对 进行更改时触发该storage事件。这对于通信目的非常方便。localStorage

可在此处找到参考:
Webstorage
Webstorage - 存储事件

于 2012-09-20T14:05:47.837 回答
30

BroadcastChannel 标准允许这样做。现在它在 Firefox 和 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);
});
于 2015-05-14T14:54:17.680 回答
13

SharedWorker 是 WHATWG/HTML5 规范,用于可以在选项卡之间进行通信的通用进程。

于 2010-04-23T23:11:04.753 回答
4

你说你的:

终极目标是制作类似于 facebook 的东西,如果你打开 4 个 facebook 标签,并在一个标签中聊天,聊天就会在每个 facebook 标签上实现,这很整洁!

这应该作为您设计的副产品发生,视图查询模型(可能是服务器)以更新聊天,而不是您必须设计跨视图通信。除非您正在处理传输大量数据,否则为什么要担心呢?似乎它会使事情复杂化而没有巨大的收益。

几年前,我发现如果我确实window.open使用了现有窗口的名称和空白 URL,我得到了对现有窗口的引用(这种行为甚至记录在 MDN上,并且 MSDN 文档上的评论表明它也适用于 IE ; 也就是说,在 2017 年,有人在 MDN 文章中添加了一个有点粗俗的注释,列出了一些限制——我没有独立验证它们)。但那是几年前的事了,我不知道在当今世界对它的支持有多普遍,当然,除非你所有的窗口都包含一个命名的iframe用于通信,通过服务器端代码唯一命名,然后通过服务器端代码与其他窗口通信......(可怕的想法:这实际上可能是可行的。存储与记录相关的“当前”窗口名称-在表中的帐户中,将列表提供给任何创建的登录该帐户的新窗口,剔除旧的非活动条目。但如果列表稍微过时,您将在搜索其他人时打开新窗口......而且我下注支持因浏览器而异。)

于 2010-02-10T13:08:43.663 回答
4

除了即将推出的SharedWorker之外,您还可以使用更广泛支持的跨文档消息传递。在这种情况下,必须有一个主窗口负责打开所有其他窗口。然后,子窗口可以其.window.openwindow.opener

如果您可以选择使用 flash,那么任何安装了 flash 的客户端实际上都支持更旧的LocalConnection (示例代码)。

其他后备方法:
用于 jQuery 的 postMessage 插件,带有 window.location.href 用于旧浏览器的后备
基于 cookie 的非即时通信解决方案

于 2012-09-11T10:44:51.900 回答
1

AFAIK,如果它们没有相同的父级,则不可能跨窗口进行通信。

如果它们都从父窗口打开,您应该能够获取父窗口的变量引用。

在父级中,像这样打开窗口:

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

在 ChildA 中,像这样访问 childB:

childB = window.opener.childA
于 2010-02-10T12:52:15.193 回答
0

我有一个巧妙的方法来做到这一点,但有限制:您应该允许您的域的弹出窗口,并且您将始终打开一个页面(作为选项卡或作为弹出窗口),这将实现窗口之间的通信。

这是一个示例: http ://test.gwpanel.org/test/page_one.html (为域启用弹出窗口后刷新页面)

这个技巧的主要特点 - 弹出窗口最后以 url 片段“#”打开,这迫使浏览器不更改窗口位置并存储所有数据。剩下的就交给 window.postMessage 了。

于 2010-03-27T19:50:22.740 回答