我正在寻找一种方法,如何在浏览器中的多个选项卡或窗口之间进行通信(在同一个域上,而不是CORS),而不留痕迹.有几个解决方案:
第一个可能是最糟糕的解决方案 - 你需要从当前窗口打开一个窗口,然后只要你打开窗户就可以进行通信.如果您在任何窗口中重新加载页面,则很可能会丢失通信.
第二种方法,使用postMessage,可能启用跨源通信,但遇到与第一种方法相同的问题.您需要维护一个窗口对象.
第三种方式,使用cookie,在浏览器中存储一些数据,这可以有效地看起来像向同一域上的所有窗口发送消息,但问题是你永远不知道所有标签是否已经读过"消息"打扫干净.您必须实现某种超时以定期读取cookie.此外,您受限于最大cookie长度,即4KB.
使用localStorage的第四种解决方案似乎克服了cookie的限制,甚至可以使用事件进行监听.接受的答案中描述了如何使用它.
编辑2018:接受的答案仍然有效,但现代浏览器有一个更新的解决方案,使用BroadcastChannel.有关如何使用BroadcastChannel在选项卡之间轻松传输消息的简单示例,请参阅其他答案.
问题:
我需要一个客户端 Javascript 解决方案(jQuery 很好),其中一个浏览器窗口/选项卡中的事件可以广播到同一域上的其他窗口/选项卡。例如,如果购物车在选项卡 A 中更新,选项卡 B 和 C 会收到通知,因此我们可以更新页面上的一些信息,或通知用户页面已过时,或类似的事情。
我试过的:
该广播信API符合我的需要,但在IE 11或Safari不起作用。
所以我尝试了这个 polyfill,这样我就可以在任何地方使用 BroadcastChannel API。它在 IE 中有效,但在 Safari 中无效(我相信 BroadcastChannel 仍未定义)。
然后我尝试了sysend.js,它使用 BroadCastChannel 如果它可用,否则使用localStorage
. 他们的演示页面在 Safari 中运行良好,但在我的网站上,我发现它在 Safari 9 中运行,但在 10-12 中不起作用(使用 BrowserStack 和一台运行 Safari 12 的真实 Mac 进行测试)。调试他们的脚本,似乎在不同选项卡中更改时应该触发的存储事件localStorage
根本不会触发。但这实际上只是当您document.domain
设置时才出现问题,我就是这样做的。
我相信这与这个旧的 Chrome 错误相同。但是 Chrome 在 2012-2017 年就有这个问题,而 Safari 显然是在 2017 年左右引入的?
我还没有发现其他人在 Safari 中讨论这个错误,但我可以很容易地证明这一点。打开两个使用相同document.domain
值的选项卡并运行这些脚本:
选项卡 A:
$(window).on("storage", function (e) …
Run Code Online (Sandbox Code Playgroud) 有没有办法,使用 Chrome DevTools 来查看除BroadcastChannel
附加message
事件侦听器之外的\xe2\x80\x99s 中发生的情况,以便我可以看到 who\xe2\x80\x99s postMessage
-ing 是什么?
javascript google-chrome google-chrome-devtools broadcast-channel
HTML5 BroadcastChannel API是在选项卡/窗口之间发送数据的绝佳解决方案。
new BroadcastChannel(name)
它们通过调用函数打开和关闭.close()
。
但是,它没有提供如何查看现有打开的 BroadcastChannel 的说明。如果我动态创建 BroadcastChannel(不使用固定频道名称),则查看当前打开的 BroadcastChannel 非常有用。
在 Google 上搜索(“查看现有广播频道 javascript”)并查看前三个结果(1、2、3)都没有提供有关如何查看所有打开的广播频道的指示。
我尝试查看该BroadcastChannel
界面,但它没有提供任何.listOpenedChannels()
功能或任何类似的内容。
如何查看现有打开的广播频道?
我正在测试BroadcastChannel功能,但遇到了麻烦。我打开两个 Chrome 窗口以及每个窗口的开发工具。我在控制台上写:
const z = new BroadcastChannel('blarg')
z.onmessage = function (ev) {console.log(ev)}
Run Code Online (Sandbox Code Playgroud)
我可以检查 z ,它已将函数保存到 onmessage 属性中,因此一切看起来都不错。然而,当我测试时:
z.postMessage('sweet')
Run Code Online (Sandbox Code Playgroud)
在其中一个控制台中,另一个控制台中没有任何显示。我希望由于两个 Chrome 窗口都订阅了广播频道blarg
,并且具有控制台记录发布消息的功能,因此我会看到该消息sweet
显示在另一个控制台中,但没有任何反应。
那么两个问题:
我不能BroadcastChannel
像这样在开发工具控制台中测试界面吗?
如果是这样,我对 BroadcastChannel 的工作原理缺少什么?
我有两个来源不同的网站。让它成为foo.com和bar.com。站点foo.comBroadcastChannel
通过名称触发消息'payment-info'
。我还有一个 iframe,托管在foo.com上,它内置于bar.com中。这是 iframe 代码:
<html><head><script type="text/javascript">
(function () {
const bc = new BroadcastChannel('payment-info');
bc.addEventListener('message', (m) => {
const data = JSON.parse(m.data);
data.channel = 'payment-info';
if (window.top !== window) {
window.top.postMessage(JSON.stringify(data), '*');
}
});
})();
</script></head><body></body></html>
Run Code Online (Sandbox Code Playgroud)
因此,iframe 订阅'payment-info'
广播频道,当它触发时,iframe 会向其父窗口(即bar.com)发布一条消息,其中包含一些信息。
在bar.com端,我只监听“message”事件并使用 JSON.parse 调用“receiveMessage”函数
window.addEventListener('message', function (message) {
receiveMessage(message);
});
Run Code Online (Sandbox Code Playgroud)
它预计可以在我的网站bar.com上的所有浏览器中运行。它不适用于 Safari 和 Firefox,但适用于 Chrome。
我将 index.html、index2.html 和 iframe.html 等多个文件中的代码组合在一起,并在一个文件中进行本地测试。index.html 和 …
如何判断广播频道是否存在及其订阅者数量?
我们有一个产品链接,一些 Chrome 页面选项卡正在订阅广播频道。想看看有多少人在听。
const bc = new window.BroadcastChannel('channel_name');
Run Code Online (Sandbox Code Playgroud)
资源:
使用Angular Typescript环境,也许它有一个库函数
javascript google-chrome typescript angular broadcast-channel
我正在使用 sessionStorage 来保存身份验证信息,并且需要将此信息复制到正在打开的其他选项卡。我创建了一个codesandbox来重现这个问题。我没有在这篇文章中包含代码,因为它很长。
当在另一个窗口中打开仪表板链接时,由于弹出错误而无法呈现。
编辑: 我已在下面包含所有必要的代码。
应用程序.js
export default function App() {
return (
<>
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/login">
<Login />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</Router>
</>
);
}
Run Code Online (Sandbox Code Playgroud)
仪表板.js
export default (props) => {
const [isLogged, setIsLogged] = useState(false);
const [email, setEmail] = useState();
const [token, setToken] = useState();
const authChannel = new BroadcastChannel("auth");
useEffect(() => {
setToken(sessionStorage.getItem("token"));
setEmail(sessionStorage.getItem("email"));
setIsLogged(sessionStorage.getItem("token") ? true : false);
authChannel.postMessage({ action: "created", source: …
Run Code Online (Sandbox Code Playgroud) javascript ×7
safari ×2
angular ×1
browser ×1
html5 ×1
iframe ×1
ipc ×1
reactjs ×1
typescript ×1