From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- .../zh-cn/web/api/channel_messaging_api/index.html | 89 ++++++++++ .../index.html" | 179 +++++++++++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 files/zh-cn/web/api/channel_messaging_api/index.html create mode 100644 "files/zh-cn/web/api/channel_messaging_api/\344\275\277\347\224\250_channel_messaging/index.html" (limited to 'files/zh-cn/web/api/channel_messaging_api') diff --git a/files/zh-cn/web/api/channel_messaging_api/index.html b/files/zh-cn/web/api/channel_messaging_api/index.html new file mode 100644 index 0000000000..6e7591d531 --- /dev/null +++ b/files/zh-cn/web/api/channel_messaging_api/index.html @@ -0,0 +1,89 @@ +--- +title: Channel Messaging API +slug: Web/API/Channel_Messaging_API +translation_of: Web/API/Channel_Messaging_API +--- +

{{DefaultAPISidebar("Channel Messaging API")}}

+ +

Channel Messaging API 允许两个不同的脚本运行在同一个文档的不同浏览器上下文(比如两个 iframe,或者文档主体和一个 iframe,使用 {{domxref("SharedWorker")}} 的两个文档,或者两个 worker)来直接通讯,在每端使用一个端口(port)通过双向频道(channel)向彼此传递消息。

+ +

{{AvailableInWorkers}}

+ +

Channel 通信的概念和用法

+ +

使用 {{domxref("MessageChannel.MessageChannel", "MessageChannel()")}} 构造函数来创建通讯信道。一旦创建,信道的两个端口即可通过 {{domxref("MessageChannel.port1")}} 和 {{domxref("MessageChannel.port2")}} 属性进行访问(都会返回 {{domxref("MessagePort")}}  对象)。创建信道的应用程序使用 port1,在另一端的程序使用 port2 —— 你向 port2 发送信息,然后携带 2 个参数(需要传递的消息,要传递所有权的对象,在这里是 port 自身)调用 {{domxref("window.postMessage")}} 方法将端口信息传递到另一个浏览器上下文。

+ +

当这些可传递的对象被传递后,他们就从之前所属的上下文中消失了。比如一个 port,一旦被发送,在原本的上下文中就再也不可用了。注意当前仅有 {{domxref("ArrayBuffer")}} 和 {{domxref("MessagePort")}} 对象可以被发送。

+ +

另一个浏览器上下文可以使用 {{domxref("MessagePort.onmessage")}} 监听信息,并使用事件的 data 属性获取消息内容。你可以通过 {{domxref("MessagePort.postMessage")}} 向原来的文档发送应答消息。

+ +

当你想要停止通过信道发送消息时,你可以调用来关闭 {{domxref("MessagePort.close")}} 端口。

+ +

更多使用这个 API 的资料参见:Using channel messaging 。

+ +

Channel 通信接口

+ +
+
{{domxref("MessageChannel")}}
+
创建一个新的发送消息的信道。
+
{{domxref("MessagePort")}}
+
控制消息信道的端口,允许从一个端口发送消息,并监听另一端消息的到来。
+
{{domxref("PortCollection")}}
+
MessagePort 数组,一种同时向多个端口广播消息的实验性解决方案。
+
+ +

例子

+ + + +

规格

+ + + + + + + + + + + + + + +
规格状态补充
{{SpecName('HTML WHATWG', 'web-messaging.html#channel-messaging', 'Channel messaging')}}{{Spec2('HTML WHATWG')}} 
+ +

浏览器兼容性

+ +
+

MessageChannel

+ +
+ + +

{{Compat("api.MessageChannel", 0)}}

+ +

MessagePort

+ +
+ + +

{{Compat("api.MessagePort", 0)}}

+
+
+
+ +

参考

+ + + +

+ +

diff --git "a/files/zh-cn/web/api/channel_messaging_api/\344\275\277\347\224\250_channel_messaging/index.html" "b/files/zh-cn/web/api/channel_messaging_api/\344\275\277\347\224\250_channel_messaging/index.html" new file mode 100644 index 0000000000..8ddfa8df8e --- /dev/null +++ "b/files/zh-cn/web/api/channel_messaging_api/\344\275\277\347\224\250_channel_messaging/index.html" @@ -0,0 +1,179 @@ +--- +title: 使用 channel messaging +slug: Web/API/Channel_Messaging_API/使用_channel_messaging +tags: + - API + - Channel messaging + - HTML5 + - MessageChannel + - MessagePort + - 指南 +translation_of: Web/API/Channel_Messaging_API/Using_channel_messaging +--- +

{{DefaultAPISidebar("Channel Messaging API")}}

+ +

Channel Messaging API 可以让运行在不同浏览器上下文中的独立脚本,连接到同一份文档(比如:两个 IFrame, 或者主文档和一个 IFrame, 或者使用同一个 {{domxref("SharedWorker")}} 的两份文档),并直接通信,通过每端一个 port 的双向频道(或管道)在两者之间传递消息。

+ +

在文本中,我们将探索这项技术的基本用法。

+ +

{{AvailableInWorkers}}

+ +

用例

+ +

Channel messaging 在这样的场景中特别有用:假如你有一个社交站点,它在主界面中通过 IFrame 内嵌了来自其他站点的内容,比如游戏,通讯录或者一个音乐播放器,有着个性化的音乐选择。当这些内容作为独立的单元时,一切都是 OK 的,但是当你想在主站点和 IFrame, 或者在不同的 IFrame 中交互时,困难就出现了。举例来说,假如你想从主站点向通讯录里添加一个联系人;或者想从游戏里,把最高分加入到个人资料;又或者,希望从音频播放器里,添加新的背景音乐到游戏中?因为浏览器使用的安全模型,使用传统的 web 技术来做这些事并不容易。你必须去考虑不同的源之间彼此是否信任,以及如何传递消息。

+ +

换个角度说,Message Channels 可以提供一个安全的通道让你在不同的浏览器上下文间传递数据。

+ +
+

提示: 要了解更多信息和思考,规范的 Ports 作为 Web 上一个对象兼容模型的基础 章节值得一读。

+
+ +

简单的例子

+ +

为了帮助你开始,我们在 Github 上传了一些 demo. 一开始可以先看我们的 channel messaging 基本示例 (也可以在线运行),它展示了一个非常简单的消息传递,发生在页面和内嵌 {{htmlelement("iframe")}} 之间。 

+ +

然后,看看我们的 multimessaging demo (在线运行),它展示了一个稍微复杂一点的例子,可以在主页面和 IFrame 之间发送多条消息。

+ +

本文中,我们重点说后面的这个例子。它看起来像是这样:

+ +

+ +

创建 channel

+ +

在例子的主页面,我们有一个简单的表单,内含一个文本输入框,用来输入要发送到 {{htmlelement("iframe")}} 的消息。我们还有一个段落,我们在稍后将会用它来显示 {{htmlelement("iframe")}} 回传回来的确认消息。

+ +
var input = document.getElementById('message-input');
+var output = document.getElementById('message-output');
+var button = document.querySelector('button');
+var iframe = document.querySelector('iframe');
+
+var channel = new MessageChannel();
+var port1 = channel.port1;
+
+// 等待 iframe 加载
+iframe.addEventListener("load", onLoad);
+
+function onLoad() {
+  // 监听按钮点击
+  button.addEventListener('click', onClick);
+
+  // 在 port1 监听消息
+  port1.onmessage = onMessage;
+
+  // 把 port2 传给 iframe
+  iframe.contentWindow.postMessage('init', '*', [channel.port2]);
+}
+
+// 当按钮点击时,在 port1 上发送一个消息
+function onClick(e) {
+  e.preventDefault();
+  port1.postMessage(input.value);
+}
+
+// 处理 port1 收到的消息
+function onMessage(e) {
+  output.innerHTML = e.data;
+  input.value = '';
+}
+ +

我们从使用 {{domxref( "MessageChannel.MessageChannel","MessageChannel()")}} 构造函数创建了一个 message channel 开始。

+ +

当 IFrame 加载完成,我们在按钮上注册了onclick 事件处理函数,在 {{domxref("MessageChannel.port1")}} 注册了 onmessage 事件处理函数。最后,我们使用 {{domxref("window.postMessage")}} 方法把 {{domxref("MessageChannel.port2")}} 传给 IFrame.

+ +

让我们来了解一下 iframe.contentWindow.postMessage 更多的工作细节。它接受三个参数:

+ +
    +
  1. 被发送的消息。对于一开始的 port 传递,这个消息可以是个空字符串,但是在例子里,我们传了 'init'.
  2. +
  3. 消息将被发送到的源(origin)。 * 意思是 "任何源".
  4. +
  5. 一个对象,它的所有权会被传给接受的浏览器上下文。在本例中,我们把 {{domxref("MessageChannel.port2")}} 传给了 IFrame, 然后它就可以用于与主页面通信了。
  6. +
+ +

当我们的按钮被点击时,我们阻止了默认的表单提交,然后把输入到输入框里的内容通过 {{domxref("MessageChannel")}} 发送给 IFrame.

+ +

在 IFrame 里接收 port 和消息

+ +

在 IFrame 里,我们有下面的 JavaScript:

+ +
var list = document.querySelector('ul');
+var port2;
+
+// 监听初始的 port 传递消息
+window.addEventListener('message', initPort);
+
+// 设置传过来的 port
+function initPort(e) {
+  port2 = e.ports[0];
+  port2.onmessage = onMessage;
+}
+
+// 处理 port2 收到的消息
+function onMessage(e) {
+  var listItem = document.createElement('li');
+  listItem.textContent = e.data;
+  list.appendChild(listItem);
+  port2.postMessage('Message received by IFrame: "' + e.data + '"');
+}
+
+ +

当收到从主页面通过 {{domxref("window.postMessage")}} 方法传来的初始化消息时,我们运行 initPort 函数。它会保存传来的 port, 并且注册了一个 onmessage 事件处理器,每当有消息通过我们的 {{domxref("MessageChannel")}} 传来时,它都会被调用。

+ +

当收到从主页面发来的消息时,我们创建一个列表项,并把它插入到这个无序列表中,然后把这个列表项的 {{domxref("Node.textContent","textContent")}} 设置为事件的 data 属性(里面包含真正的消息)。

+ +

然后,我们通过在初始化时传到 IFrame 的 {{domxref("MessageChannel.port2")}} 上调用 {{domxref("MessagePort.postMessage")}} 来使用 message channel 发送一个确认消息给主页面。

+ +

在主页面中接收确认消息

+ +

回到主页面,我们来一起看看 onmessage 事件处理函数。

+ +
// 处理 port1 上收到的消息
+function onMessage(e) {
+  output.innerHTML = e.data;
+  input.value = '';
+}
+ +

当收到从 IFrame 发来的确认消息,说明原始消息被成功接收时,它把确认消息输出到段落中,并清空输入框,为输入下一个要被发送的消息做准备。

+ +

规范

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML WHATWG', 'web-messaging.html#channel-messaging', 'Channel messaging')}}{{Spec2('HTML WHATWG')}}
+ +

浏览器兼容性

+ +
+

MessageChannel

+ +
+ + +

{{Compat("api.MessageChannel", 0)}}

+ +

MessagePort

+ +
+ + +

{{Compat("api.MessagePort", 0)}}

+
+
+
+ +

参见

+ + -- cgit v1.2.3-54-g00ecf