什么是在同一浏览器的不同标签页/窗口之间进行JavaScript通信最可靠的方式?例如,当第二个标签页开始音频播放时,第一个标签页可以知道并停止它的播放器。
我正在构建一个带有音乐播放器的网站... 因此,如果您打开两个网站标签页,您可能会在两个标签页上同时播放音乐。这显然很糟糕,因此我正在寻找解决方案。
什么是在同一浏览器的不同标签页/窗口之间进行JavaScript通信最可靠的方式?例如,当第二个标签页开始音频播放时,第一个标签页可以知道并停止它的播放器。
我正在构建一个带有音乐播放器的网站... 因此,如果您打开两个网站标签页,您可能会在两个标签页上同时播放音乐。这显然很糟糕,因此我正在寻找解决方案。
如果您需要更现代的解决方案,请查看 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
出于历史原因,您可以将旧方案保留在下方,并更新为现代解决方案。
您可以使用广播通道API发送和接收消息。 https://developer.mozilla.org/zh-CN/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在浏览器窗口之间(包括选项卡)进行通信。
下面是发送者和接收者的示例:
sender.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>
receiver.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>
setTimeout
- 这样做会使用 eval
。相反,使用 setTimeout(updateMessage, 100)
直接传递函数。 - Yi JiangsetInterval()
。 - Julian F. Weinert我认为您不需要使用cookies。每个文档的JavaScript代码都可以访问其他文档元素。因此,您可以直接使用它们来共享数据。
您的第一个窗口w1打开w2并保存引用
var w2 = window.open(...)
在w2中,您可以使用window
的opener
属性访问w1。
您可以通过本地存储API来实现。请注意,这仅适用于两个选项卡之间的操作。您无法将发送方和接收方都放在同一页上:
在发送方页面上:
localStorage.setItem("someKey", "someValue");
接收方页面:
$(document).ready(function () {
window.addEventListener('storage', storageEventHandler, false);
function storageEventHandler(evt) {
alert("storage event called key: " + evt.key);
}
});
还有一项实验性技术称为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"});
显然这是实验性技术,并且尚未在所有浏览器上得到支持。
以下窗口(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", "*");
即使在 HTML5 之前,如果文档属于相同的来源,则可以支持在不同的 JavaScript 执行上下文之间进行通信。
如果不是这种情况或者您没有对其他 Window
对象的引用,则可以使用 HTML5 引入的新的postMessage API。我在 Stack Overflow 答案中对这两种方法进行了详细说明。
如果窗口之间存在父子关系,您可以在它们之间进行通信(无论是标签式还是非标签式窗口)。
创建并更新一个子窗口:
<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
对象与生成它的父窗口进行通信,因此您可以从任一窗口控制音乐播放器。
我发现使用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
函数,可在同一页上执行事件。
即使是最新版本,也支持管理窗口,向特定窗口发送消息或获取窗口/选项卡列表。