网页间传递消息的几种方法

postMessage

//  发送消息
win = document.querySelector("iframe").contentWindow;
win.postMessage({ name: "hhh", age: 11 }, "http://127.0.0.1:5500");

//  获取消息
window.onmessage = function (event) {
  //  获取消息
  console.log(event.data);
  //  获取源
  console.log(event.origin);
};
// postMessage的兼容性较好,可以跨域传递消息,但是窗口必须是父子关系

BroadcastChannel

// 收消息页面核心代码
var bc = new BroadcastChannel("test_channel");

bc.onmessage = function (ev) {
  console.log(ev);
  bc.postMessage({
    msg: `receive message : ${ev.data.msg}`
  });
};

// 发消息页面核心代码
var bc = new BroadcastChannel("test_channel");

bcBtn.onclick = function () {
  bc.postMessage({
    msg: "helloWorld"
  });
};
bc.onmessage = function (ev) {
  console.log(ev.data.msg);
};

storage

// 监听消息事件
window.addEventListener("storage", function (e) {
  let msg = e.key + " 键已经从 " + e.oldValue + " 改变为 " + e.newValue + ".";
  console.log(msg);
  outputScreen.innerHTML = msg;
});
// 触发消息事件
localStorage.setItem("test", Math.floor(Math.random() * 10000));

shareWorker

worker 的一种,通信页面必须同源 同Worker的api一样,传入js的url,就可以注册一个 sharedWorker 实例 与普通 Worker 的不同点:

  1. 同一个js url 只会创建一个 sharedWorker,其他页面再用同url创建,会复用共享。
  2. sharedWorker通过port来发送和接收消息
// 页面
// page.js
let myWorker = new SharedWorker('worker.js');
// page通过worker port发送消息
myWorker.port.postMessage('哼哼');
// page通过worker port接收消息
myWorker.port.onmessage = (e) => console.log(e.data);

// 引入的JS部分
// worker.js
onconnect= function(e) {
	const port = e.ports[0];
	port.postMessage('哈嘿');
	port.onmessage = (e) => {
		console.log(e.data);
	}
}

如果要实现多页面广播只需要将 worker.js 改成

// worker.js
const portPool = [];
onconnect = function(e) {
  var port = e.ports[0];
  portPool.push(port);
  port.onmessage = function(e) {
    console.log(e);
    if (e.data === 'TO BE CLOSED') {
      const index = ports.findIndex(p => p === port);
      portPool.splice(index, 1);
    }
    var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
    port.postMessage(workerResult);
  }
}

function boardcast(message) {
	portPool.forEach(port => {
		port.portMessage(port);
	})
}

那么 setInterval(() => boardcast(Date.now()), 1000); 一句话就可以实现广播时间了。

window.opener

// window.opener返回的是打开当前窗口的那个窗口的引用
// 如果不是从任何窗口打开,则opener为null
if (window.opener) {
  window.opener.document.getElementById("contentScreen").innerHTML =
    "change from open window";
}
// 该方法受同源策略限制