热线你和我,这是一条情感的线路,属於你和我。
昨天我们认识了 PostMessage,它可以让我们在两个页面之间传递讯息,只要有地址(Domain Origin),就可以送信给对方,而对方只要有收信的机制就能够获得讯息,甚至可以回信。但这有个坏处,也就是当我们建立了收信机制後,可能会有来自四面八方的讯息寄过来,那就必须要做一个过滤的动作。但今天的 MessageChannel 却可以解决这个问题。
有些 Package 或 Library 有可能会使用 PostMessage 在你的网页文件中执行讯息传递,这些讯息也是需要过滤的。
MessageChannel 就像是在两个页面中建立一个热线系统,这样就不会再那些不想收到讯息,只有绑定的双方可以透过 MessageChannel 来进行沟通,就像是一个专属的频道。如果以图像来表示整个频道建立的过程的话,会像是下图这样:
先来看第一步「建立频道」,MessageChannel
本身是一个 Class
,所以我们用关键字 new
来创建一个新的 MessageChannel 物件,就这麽简单明了,而且也不需要传入任何参数。
const msgChannel = new MessageChannel();
而当 MessageChannel 建立後,它底下就会有两个唯读属性可以取得,分别是 port1
和 port2
,也就是图片中的两部手机:
console.log(msgChannel.port1);
console.log(msgChannel.port2);
在建立频道之後,目前两部手机(Port)都还是由目前的页面所掌控,我们需要将其中一部手机(Port)传递给我们想建立通讯的另一个页面中。
<!-- 这里是 pageA.html -->
<iframe src="pageB.html" width="480" height="320"></iframe>
<script>
let messagePort;
const iframe = document.querySelector("iframe");
iframe.addEventListener("load", function () {
// 建立频道,并取得 port1、port2
const { port1, port2 } = new MessageChannel();
// 将 port1 存在全域变数中
messagePort = port1;
// 将 port2 送给 pageB
const msg = "这是 pageA 送来的手机";
iframe.contentWindow.postMessage(msg, location.origin, [port2]);
});
</script>
虽然已经建立了 MessageChannel,但「送手机」的这一步还是要靠一般的方式送过去,而手机(Port)的部分必须放在之前介绍 postMessage
时没说的第三个参数中:
port
,藉此产生两个页面的讯息通道。再来,pageA 还需要先做好准备,才不会漏接了 pageB 传过来的讯息,也就是要监听 message
事件,但是这次不再是用 window
监听了,而是使用 port1.onmessage
:
<!-- 这里是 pageA.html -->
<iframe src="pageB.html" width="480" height="320"></iframe>
<script>
let messagePort;
const iframe = document.querySelector("iframe");
iframe.addEventListener("load", function () {
const { port1, port2 } = new MessageChannel();
messagePort = port1;
// 用 port1 监听 message 事件
messagePort.onmessage = function (event) {
console.log(event.data);
};
const msg = "这是 pageA 送来的手机";
iframe.contentWindow.postMessage(msg, location.origin, [port2]);
});
</script>
再来就是要在 pageB 接收这个「寄送手机」的信息,只要在传送端有在 postMessage
放入 transfer
这个参数,接收端就可以在 Event 物件中的 ports
属性取得「这部手机」。
在收到这部手机(Port)後,我们可以先存起来,然後为它建立事件,以便未来在频道中收到 pageA 时才会对应的操作。除此之外,我们还可以顺势用这部手机马上打回去,跟 pageA 说我们已经拿到手机(Port)了。
<!-- 这里是 pageB.html -->
<div class="output">default content</div>
<script>
let messagePort;
const output = document.querySelector(".output");
window.addEventListener("message", function (event) {
if (!event.ports || !event.ports.length) return;
// 将讯息文字显示在页面上
output.innerHTML = event.data;
// 将 port2 存在全域变数中
messagePort = event.ports[0];
// 用 port2 监听 message 事件
messagePort.onmessage = function (port_event) {
output.innerHTML = port_event.data;
};
// 用 port2 送出讯息
messagePort.postMessage("收到手机罗!");
});
</script>
前面我们已经把前置作业全部都完善了,包括建立频道、传送埠口(Port)、事件监听,接下来我们就可以享受信息畅通的专属热线了:
<!-- 这里是 pageA.html -->
<button onclick="sendMessage()">send message</button>
<iframe src="pageB.html" width="480" height="320"></iframe>
<script>
let messagePort;
// ... 省略其他 code
function sendMessage() {
messagePort.postMessage("来自 pageA 的讯息");
}
</script>
<!-- 这里是 pageB.html -->
<button onclick="sendMessage()">send message</button>
<div class="output">default content</div>
<script>
let messagePort;
// ... 省略其他 code
function sendMessage() {
messagePort.postMessage("来自 pageB 的讯息");
}
</script>
是不是对 PostMessage 又有新的一层认识呢?但你以为就只有这样吗?其实明天还会介绍 BroadcastChannel,除了可以建立专属热线之外,还可以建立广播系统!
Search Console 中数百数千个数字中,若只拿一个数字给老版看的话,该看那一个,答案很简单...
线上模型的偏差漂移 Amazon SageMaker Clarify 偏差监控的功能可以帮助资料科学...
分享一个好用的进销存软件 eztool , 用这软件处理客人订单有一些时间了, 非常的方便又好用, ...
此系列文章会同步发文到个人部落格,有兴趣的读者可以前往观看喔。 今天要跟大家分享如何测试提交表单,...
Day4有跟大家提到for回圈,但并非所有条件都必须用for回圈来写,这个时候我们就可以利用whil...