使用 Javascript 进行跨表通信
什么是交叉表通信?
局限性/陷阱
这有什么用?
示例/演示
更多用例
结论
资源
大约一个月前,工作中出现了一个有趣的问题:如何监听另一个标签页中正在提交的表单?如果表单在同一个标签页中,那就简单多了。但我还想知道,我能否在这两个或多个标签页之间发送消息。
什么是交叉表通信?
跨标签页通信是指多个标签页、窗口、框架或 iframe(以下简称实例)向其他实例发送和接收“消息”的能力。
局限性/陷阱
但这也有一些缺点。这种方法仅适用于同源域名。
您无法在 HTTP 和 HTTPS 协议下使用此功能。
您无法在不同的主机上使用此功能。
您无法在不同的端口上使用此功能。
这有什么用?
在进行演示之前,我想先解释一下它的用途。有时用户会同时打开多个网站实例,而我们如何处理他们的体验就显得至关重要。
例如,Dan Abramov 的博客https://overreacted.io/提供了一个深色模式/浅色模式的切换开关。使用此功能,您无需刷新页面即可将所有打开的实例切换到首选主题。
示例/演示
示例 1 - 本地存储
其工作原理是在应用程序加载时设置/修改本地存储或会话存储中的值。当这种情况发生时,会触发一个事件,任何其他实例都可以监听该事件。此事件包含诸如被修改的键、先前的值、新值等等信息。如果您熟悉 React,这类似于在类生命周期方法 componentDidUpdate 中比较先前 props 和当前 props 的方式。
示例 1 的缺点
使用这种方法也有一些缺点。首先,除非对象被字符串化,否则无法将其存储在本地存储/会话存储中。这意味着您必须解析这些值,虽然这可能不是什么大问题,但依我之见,这并非理想之选。
第二个缺点是,如果某个值被更新为相同的值,则不会触发该事件。在我的示例中,我通过将键设置loaded为 Date.now() 来规避了这个限制。
示例 2 - 广播频道
在这个例子中,我使用的是 BroadcastChannel API。为此,你需要创建一个新的 BroadcastChannel,并为其指定一个名称(类似于 IRC 频道)。
订阅频道后,您将获得一个 BroadcastChannel 对象实例,本例中我们使用了该对象的两个部分。您可以使用该postMessage函数发送消息,也可以将函数附加到该onmessage属性。
与示例 1 类似,您在一个实例中发送的消息将在其他实例中被接收。此外,您还可以多次订阅同一频道。
示例 2 的缺点/优点
与示例 1 不同,您可以发布完整的对象、数组和其他数据片段。
然而,示例 2 稍微复杂一些,而且根据你想要做的事情,可能有点过度设计了。
对 BroadcastChannel API 的支持也十分有限。与本地存储(全球支持率达 92%)相比,BroadcastChannel 的支持率仅为 76% 左右。Chrome 和 Firefox 都支持 BroadcastChannel,而 IE、Safari 和 Edge 则不支持。(Chromium Edge 虽然支持 BroadcastChannel,但截至本文发布时仍处于 Beta 测试阶段。)
更多用例
这可以在内容管理系统 (CMS) 中使用,以便在用户尝试修改某些内容时告知他们已经打开了一个实例,或者在选项卡之间保持同步。
登录时可以解锁身份验证/锁定内容,这样其他窗口就不会不同步。
更改个人资料图片
iframe 之间的通信。
更改网站主题,并将这些更改同步到所有选项卡。
结论
我不认为这会是突破性的创新,也不会改变我们开发应用程序的方式。但我确实认为,在应用程序的某些功能中应用这项技术可以改善用户体验。
如果您认为它还有其他用途,欢迎告诉我!
资源
CanIUse - 本地存储
CanIUse - 广播频道
MDN - 广播频道