使用 JavaScript 的浏览器选项卡/窗口之间的通信

IT技术 javascript browser
2021-02-05 21:50:24

让 JavaScript 在同一浏览器的选项卡/窗口之间进行通信的最可靠方法是什么?例如,当 Tab 2 开始播放音频时,Tab 1 以某种方式知道这一点并可以暂停其播放器。

我正在建立一个带有音乐播放器的网站...所以目前如果您打开该网站的两个选项卡,您可以在这两个选项卡上播放音乐。这显然很糟糕,所以我正在努力寻找解决方案。

6个回答

如需更现代的解决方案,请查看https://stackoverflow.com/a/12514384/270274

引用:

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

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

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

参考:
http : //dev.w3.org/html5/webstorage/
http://dev.w3.org/html5/webstorage/#the-storage-event

@Anas:链接已死。新网址:blogs.msdn.microsoft.com/ieinternals/2009/09/15/...
2021-03-11 21:50:24
这比公认的解决方案要好。这不需要您不断检查新信息,没有延迟,并且使您能够接收所有事件。
2021-03-24 21:50:24
我在 IE11 上的 localStorage 有问题,请参阅这篇文章(我遇到了第 3 点)blogs.msdn.com/b/ieinternals/archive/2009/09/16/... 所以 cockie 解决方案更好(至少对于 IE)。我也尝试禁用 cockies 但它仍然有效(这是在 IE 11 上)。
2021-03-30 21:50:24
这解决了很多问题(比 BroadcastChannel 实现的更广泛),但请注意,如果用户在同一浏览器中打开 2 个“发件人”选项卡,您将有一些惊喜:拥有 1 个公共通信渠道可能会引起一些惊喜
2021-04-01 21:50:24
2021-04-06 21:50:24

更新到现代解决方案,由于历史原因将旧解决方案保留在下方。

您可以使用广播频道 API 来发送和接收消息 https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API

// Connection to a broadcast channel
const bc = new BroadcastChannel('test_channel');

// Example of sending of a very simple message
// It doesn't have to be a string, it could be a JS object
bc.postMessage('This is a test message.');

要接收消息:

// A handler that only logs the event to the console:
bc.onmessage = function (ev) {
  console.log(ev);
}

并关闭通道:

// Disconnect the channel
bc.close();

这是历史悠久的老方法,对现代浏览器使用上述方法!

您可以使用 cookie 在浏览器窗口(以及选项卡)之间进行通信。

以下是发送方和接收方的示例:

发件人.html

<h1>Sender</h1>

<p>Type into the text box below and watch the text 
   appear automatically in the receiver.</p>

<form name="sender">
<input type="text" name="message" size="30" value="">
<input type="reset" value="Clean">
</form>

<script type="text/javascript"><!--
function setCookie(value) {
    document.cookie = "cookie-msg-test=" + value + "; path=/";
    return true;
}
function updateMessage() {
    var t = document.forms['sender'].elements['message'];
    setCookie(t.value);
    setTimeout(updateMessage, 100);
}
updateMessage();
//--></script>

接收器.html:

<h1>Receiver</h1>

<p>Watch the text appear in the text box below as you type it in the sender.</p>

<form name="receiver">
<input type="text" name="message" size="30" value="" readonly disabled>
</form>

<script type="text/javascript"><!--
function getCookie() {
    var cname = "cookie-msg-test=";
    var ca = document.cookie.split(';');
    for (var i=0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(cname) == 0) {
            return c.substring(cname.length, c.length);
        }
    }
    return null;
}
function updateMessage() {
    var text = getCookie();
    document.forms['receiver'].elements['message'].value = text;
    setTimeout(updateMessage, 100);
}
updateMessage();
//--></script>
Tomáš Zato,请注意答案是从 2010 年开始的——当时并非所有浏览器都支持 HTML5,并且 IE6 和 IE7 的份额相当高。现在有更好的解决方案。
2021-03-26 21:50:24
我也建议使用 setInterval()
2021-04-01 21:50:24
我也想过类似的事情,但希望有比 cookie/setTimeout 更好的解决方案。然而,这可能只是唯一的解决方案。谢谢
2021-04-04 21:50:24
不要将字符串传递给setTimeout- 您正在使用eval它。相反,直接将函数传递给setTimeout(updateMessage, 100)
2021-04-06 21:50:24
我在 IE11 上的 localStorage 有问题,请参阅这篇文章(我遇到了第 3 点)blogs.msdn.com/b/ieinternals/archive/2009/09/16/... 所以 cockie 解决方案更好(至少对于 IE)。我也尝试禁用 cockies 但它仍然有效(这是在 IE 11、IE 10、IE 9 上)。
2021-04-08 21:50:24

还有一种叫做实验性的技术Broadcast Channel API,它是专门为具有相同起源的不同浏览器上下文之间的通信而设计的。您可以向另一个浏览器上下文发布消息和从另一个浏览器上下文接收消息,而无需引用它:

var channel = new BroadcastChannel("foo");
channel.onmessage = function( e ) {
  // Process messages from other contexts.
};
// Send message to other listening contexts.
channel.postMessage({ value: 42, type: "bar"});

显然,这是一项经验性技术,尚不支持所有浏览器。

它不再是实验性的,即使 Edge 可能还没有实现它(它?在 MDN 中标记
2021-03-16 21:50:24
Edge 现在有了。
2021-03-28 21:50:24

我认为你不需要饼干。每个文档的 JavaScript 代码都可以访问其他文档元素。因此您可以直接使用它们来共享数据。

您的第一个窗口 w1 打开 w2 并保存参考

var w2 = window.open(...)

在 w2 中,您可以使用 的 opener 属性访问 w1 window

使用 Cookie?吃它们,享受吧!有一个更简单的方法!只需访问另一个窗口的 var。在 w1 中有一个值 var,从 w2 访问它 whit window.opener.value !
2021-03-12 21:50:24
只是为了让每个人都知道,这是错误的答案,正如@Ferdinak 已经试图说的那样。您没有对用户打开的选项卡的引用。
2021-03-18 21:50:24
有趣是无关紧要的。这首先是一个问答网站。人们来到此页面寻找提问者问题的答案。如果你想分享一些有趣的东西,你应该考虑写一个新的 wiki 风格的问题。
2021-03-26 21:50:24
假设用户将它们全部打开。在这种情况下有任何类似的解决方案吗?
2021-04-01 21:50:24
@jonas.ninja IMO 关于如何打开选项卡的问题并不是 100% 清楚,因此即使它不是通用答案,这也是一个完全有效的答案。
2021-04-03 21:50:24

您可以通过本地存储 API 执行此操作。请注意,这仅适用于两个选项卡之间。您不能将发送方和接收方放在同一页面上:

在发件人页面上:

localStorage.setItem("someKey", "someValue");

在接收器页面上:

    $(document).ready(function () {

        window.addEventListener('storage', storageEventHandler, false);

        function storageEventHandler(evt) {
            alert("storage event called key: " + evt.key);
        }
    });
我打算使用这种方法,直到我发现 webbrowser 控件不会触发“存储”事件处理程序方法。不知道为什么。也许是错误。
2021-03-11 21:50:24
感谢您提供此解决方案。让我的一天。它不适用于 file:/// 协议,但适用于有效域。另一个类似的演示html5demos.com/storage-events
2021-03-20 21:50:24
您无需等待 DOM 准备就绪即可访问 localStorage
2021-03-30 21:50:24