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

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

我正在建立一个有音乐播放器的网站... 所以现在如果你打开两个标签页,你就可以同时在两个页面上播放音乐。 很明显情况不妙,所以我在想办法。

158068 次浏览

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

您可以使用广播频道 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 在浏览器窗口(以及选项卡)之间进行通信。

下面是一个发送方和接收方的例子:

发件人

<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>

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

第一个窗口 w1打开 w2并保存引用

var w2 = window.open(...)

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

使用 Flash,你可以在任何窗口、 任何浏览器(是的,从火狐到运行时的 Internet Explorer)之间进行通信... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ..。

要获得更现代的解决方案,请查看 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

如果文档来源相同,甚至在 HTML5之前就支持在不同的 JavaScript 执行上下文之间进行通信。

如果没有或者没有对其他 Window对象的引用,那么可以使用 HTML5引入的新 邮件 API。我在 这个堆栈溢出的答案中对这两种方法都做了一些阐述。

我发现了一种使用 HTML5本地存储的不同方法,我创建了一个包含 API 等事件的库:

sysend.on('foo', function(message) {
console.log(message);
});
var input = document.getElementsByTagName('input')[0];
document.getElementsByTagName('button')[0].onclick = function() {
sysend.broadcast('foo', {message: input.value});
};

Https://github.com/jcubic/sysend.js

它将向所有其他页面发送消息,但不会发送到当前页面。

编辑:

最新版本的库也支持广播信道通信,但它仍然在 IE11中工作,只支持本地存储。它还支持跨源通信(不同的域) ,但只支持少量代码。

最新的 API 还支持在同一页面上执行事件的 emit函数。

即使是最新版本,也支持管理窗口、向特定窗口发送消息或获取窗口/选项卡列表。

如果窗口具有子-父关系,则可以在它们之间进行通信(选项卡式或非选项卡式)。

创建和更新子窗口:

<html>
<head>
<title>Cross window test script</title>
<script>
var i = 0;
function open_and_run() {
var w2 = window.open("", "winCounter");
var myVar=setInterval(function(){myTimer(w2)},1000);
}


function myTimer(w2) {
i++;
w2.document.body.innerHTML="<center><h1>" + i + "</h1><p></center>";
}
</script>
</head>
<body>
Click to open a new window
<button onclick="open_and_run();">Test This!</button>
</body>
</html>

子窗口可以使用 parent对象与生成它的父窗口进行通信,这样您就可以从任何一个窗口控制音乐播放器。

在这里可以看到它的实际运作: https://jsbin.com/cokipotajo/edit?html,js,output

您可以通过本地存储 API 实现这一点。注意,这只能在两个选项卡之间工作。你不能把发送者和接收者放在同一个页面上:

在发件人页面:

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

在接收器页面:

    $(document).ready(function () {


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


function storageEventHandler(evt) {
alert("storage event called key: " + evt.key);
}
});

下面的窗口(w1)打开另一个窗口(w2)。任何窗口都可以向另一个窗口发送/接收消息。因此,理想情况下,我们应该验证消息是否来自我们打开的窗口(w2)。

在 W1

var w2 = window.open("abc.do");
window.addEventListener("message", function(event){
console.log(event.data);
});

在 w2(abc. do)

window.opener.postMessage("Hi! I'm w2", "*");

还有一种被称为 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"});

显然,这是一种经验性的技术,并不是所有浏览器都支持。