@actualwave/messageport-dispatcher 中文文档教程

发布于 4年前 浏览 8 项目主页 更新于 3年前

MessagePortDispatcher

构建状态Coverage Status

MessagePortDispatcher 是用于跨源通信的扩展 API。 它利用 MessagePort API 可在 window 对象上发送自定义进入/来自

两个

Installation

易于安装 npm 包管理器

npm install --save @actualwave/messageport-dispatcher

yarn 包管理器

yarn add @actualwave/messageport-dispatcher

Usage

注意:MessagePortDispatcher 分发包包含 dist/ 文件夹,包被包装到 UMD 包装器中,因此它可以与任何 AMD 模块加载器一起使用, nodejs require() 或没有任何。

要开始使用 EventDispatcher,只需实例化它

const dispatcher = new MessagePortDispatcher(iframe.contentWindow);

作为第一个参数,它的构造函数接受实现 MessagePort< 的消息传递方法的对象/a> 界面。

可以使用 Window 对象或 Dedicated Worker 与通信通道的另一端进行通信(将事件发送到 IFRAME 中的脚本或从 IFRAME 或发送到 Worker)。 要让自定义事件在双方都起作用,应该从通信通道的双方创建 MessagePortDispatcher 实例。 在外部文档中传递 IFRAME 的窗口对象

const frameDispatcher = new MessagePortDispatcher(iframeNode.contentWindow);
frameDispatcher.addEventListener('initialized', () => {
    console.log('Ok, we can start communication.');
});

在 IFRAME 中使用 window.self

const dispatcher = MessagePortDispatcher.self();
dispatcher.dispatchEvent('initialized');

MessagePortDispatcher.self()MessagePortDispatcher.parent()返回的实例code>MessagePortDispatcher.top() 在内部缓存,所以总是返回相同的实例。

可以为任何对象编写一个适配器并将其传递给 MessagePortDispatcher

const target = {
    postMessage: (data, origin) => {
        console.log('Message sent', data);
        window.postMessage(data, origin);
    },
    addEventListener: (eventType, handler) => {
        console.log('Event listener added to ', eventType);
        window.addEventListener(eventType, handler);
    },
    removeEventListener: (eventType, handler) => {
        console.log('Event listener removed from ', eventType);
        window.removeEventListener(eventType, handler);
    }
};
const dispatcher = new MessagePortDispatcher(target);

创建其实例后,您可以将事件发送到 iframe

dispatcher.dispatchEvent('someEvent', {someData: 'anything here'});

并在另一端捕获它

dispatcher.addEventListener('someEvent', (event) => {
console.log('Data received', event.data);
});

When MessagePortDispatcher.dispatchEvent() 调用,实际上是调用postMessage() 方法向对方传递消息。 因此,您可以使用 MessagePortDispatcher 发送和接收自定义事件,而不是使用 postMessage 和监听 message 事件。

当 MessagePortDispatcher 实例化时,它会创建两个 EventDispatcher,一个用于传入事件,第二个用于传出事件。 由于 Window 对象为双方触发相同的 message 事件,在幕后 MessagePortDispatcher 为每个事件添加自己的 ID,如果接收到的事件具有相同的 ID,它将通过 sender(传出事件)EventDispatcher,否则通过 receiver(传入事件)。 这将不起作用,事件 someEvent 将在另一端触发,但不会针对此调度程序:

dispatcher.addEventListener('someEvent', () => {
    console.log('Some Event Received!');
});
dispatcher.dispatchEvent('someEvent');

如果您想监听传出事件,请使用 sender

dispatcher.sender.addEventListener('someEvent', () => {
    console.log('Some Event Received!');
});
dispatcher.dispatchEvent('someEvent');

使用相同的事件类型通信渠道的双方不会混淆它们,因为它们会被不同的调度员解雇。

MessagePortDispatcher 公开了来自 receiver EventDispatcher 的方法,以便于使用和使用 MessagePort.postMessage() 发送事件的自定义 dispatchEvent() 方法。 这两个调用是等价的:

dispatcher.addEventListener('someEvent', () => {});
dispatcher.receiver.addEventListener('someEvent', () => {});

但是这些行做了不同的事情:

dispatcher.dispatchEvent('someEvent');
dispatcher.sender.dispatchEvent('someEvent');

sender.dispatchEvent() 只会从发送者 EventDispatcher 触发事件,但是 MessagePortDispatcher.dispatchEvent() 会实际发送消息通过 postMessage() 发送到另一端。

由于 MessagePortDispatcher 在源之间传递数据,它只能发送可以转换为 JSON 的简单数据(即无法通过引用发送任何数据)。 在发送事件之前,它会检查其数据属性值。 如果此值具有方法 toJSON(),它将使用它并按原样发送返回的数据。 在其他情况下,该值将在发送之前转换为 JSON 字符串,并在接收时转换回来。 使用 toJSON() 方法时,开发人员有责任查找嵌套数据对象并将所有内容转换为可传输的简单对象。

项目在 example 文件夹中包含示例,它展示了在与框架通信时如何使用 MessagePortDispatcher。

API

MessagePortDispatcher constructor arguments

  • target:Object - Requred, target object, should have postMessage(), addEventListener(), removeEventListener() methods, asdescribed in MessagePort docs.
  • customPostMessageHandler:Function - will be used to call target.postMessage()
  • receiverEventPreprocessor:Function - Optional, allows pre-processing of events and their data before firing event.
  • senderEventPreprocessor:Function - Optional, , allows pre-processing of events and their data before passing them to postMessage or customPostMessageHandler.

MessagePortDispatcher instance members

  • targetOrigin:String
  • sender:EventDispatcher - fires outgoing events that are passed to postMessage()
  • receiver:EventDispatcher - fires incoming events received from other origin
  • target:Object - target object that is used for communication
  • dispatcherId:String - unique ID of current MessagePortDispatcher instance
  • addEventListener(eventType:String, listener:Function):void - method copied from receiver EventDispatcher for easier access
  • hasEventListener(eventType:String):Boolean - method copied from receiver EventDispatcher for easier access
  • removeEventListener(eventType:String, listener:Function):void - method copied from receiver EventDispatcher for easier access
  • removeAllEventListeners(eventType:String):void - method copied from receiver EventDispatcher for easier access
  • dispatchEvent(event:Object):void - does not fire event, it sends event to postMessage(). Can be used with two arguments:
  • - dispatchEvent(eventType:String, data?:Object):void

MessagePortTarget

用作 MessagePortDispatcher 代理目标的类,当您有两个对象用于发送和接收消息时,它很有用。 例如,当您有一个包含来自另一个来源的内容的 iframe 时,您可以将 iframe.contentWindow 设置为发送方对象并将自己的窗口设置为接收方。 发送者对象必须包含 postMessage() 方法和接收者对象——addEventListener()removeEventListener() 方法。 将发送者和接收者都传递给 MessagePortTarget 构造函数,然后可以为 MessagePortDispatcher 提供它的实例。

const frameDispatcher = new MessagePortDispatcher(new MessagePortTarget(iframeNode.contentWindow, window));

它还接受用于批量发送和接收的发送者和接收者列表。

const frameDispatcher = new MessagePortDispatcher(new MessagePortTarget([
  iframe1.contentWindow,
  iframe2.contentWindow,
  iframe3.contentWindow
  ], window));

MessagePortDispatcher

Build StatusCoverage Status

MessagePortDispatcher is extended API for cross-origin communication. It utilizes MessagePort API available on window object to send custom events into/from <IFRAME/> or other target that implements MessagePort interface. MessagePortDispatcher uses two EventDispatcher's for incoming and outgoing events internally.

Demo with two <iframe/>'s talking to each other

Installation

Easy to install with npm package manager

npm install --save @actualwave/messageport-dispatcher

with yarn package manager

yarn add @actualwave/messageport-dispatcher

Usage

Note: MessagePortDispatcher distribution package contains dist/ folder with package wrapped into UMD wrapper, so it can be used with any AMD module loader, nodejs require() or without any.

To start using EventDispatcher, just instantiate it

const dispatcher = new MessagePortDispatcher(iframe.contentWindow);

As first argument its constructor accepts object that implements messaging methods of MessagePort interface.

Window object or Dedicated Worker can be used, to communicate with other side of communication channel(send event to script in IFRAME or from IFRAME or to Worker). To have custom events working on both sides, MessagePortDispatcher instances should be created from both sides of communication channel. In outer document pass IFRAME's window object

const frameDispatcher = new MessagePortDispatcher(iframeNode.contentWindow);
frameDispatcher.addEventListener('initialized', () => {
    console.log('Ok, we can start communication.');
});

In IFRAME use window.self

const dispatcher = MessagePortDispatcher.self();
dispatcher.dispatchEvent('initialized');

Instances returned from MessagePortDispatcher.self(), MessagePortDispatcher.parent() and MessagePortDispatcher.top() are cached internally, so will always return same instance.

Its possible to write an adapter for any object and pass it into MessagePortDispatcher

const target = {
    postMessage: (data, origin) => {
        console.log('Message sent', data);
        window.postMessage(data, origin);
    },
    addEventListener: (eventType, handler) => {
        console.log('Event listener added to ', eventType);
        window.addEventListener(eventType, handler);
    },
    removeEventListener: (eventType, handler) => {
        console.log('Event listener removed from ', eventType);
        window.removeEventListener(eventType, handler);
    }
};
const dispatcher = new MessagePortDispatcher(target);

Once its instance was created, you can send events into iframe

dispatcher.dispatchEvent('someEvent', {someData: 'anything here'});

and catch it on other side

dispatcher.addEventListener('someEvent', (event) => {
console.log('Data received', event.data);
});

When MessagePortDispatcher.dispatchEvent() called, it actually calls postMessage() method to pass message to other side. So instead of using postMessage and listening to message event, with MessagePortDispatcher you can send and receive custom events.

When MessagePortDispatcher instantiated, it creates two EventDispatcher's, one for incoming events and second for outgoing. Since Window object fires same message event for both sides, under the hood MessagePortDispatcher adds own ID to each event and if received event has same ID, it will be fired viasender(outgoing event) EventDispatcher, otherwise via receiver(incoming event). This will not work, event someEvent will be fired on other side but not for this dispatcher:

dispatcher.addEventListener('someEvent', () => {
    console.log('Some Event Received!');
});
dispatcher.dispatchEvent('someEvent');

If you want to listen for outgoing events, use sender:

dispatcher.sender.addEventListener('someEvent', () => {
    console.log('Some Event Received!');
});
dispatcher.dispatchEvent('someEvent');

Using same event types on both sides of communication channel will not mix them, since they will be fired from different dispatchers.

MessagePortDispatcher has exposed methods from receiver EventDispatcher for easier usage and custom dispatchEvent() method that sends events using MessagePort.postMessage(). These two calls are equivalent:

dispatcher.addEventListener('someEvent', () => {});
dispatcher.receiver.addEventListener('someEvent', () => {});

But these lines do different things:

dispatcher.dispatchEvent('someEvent');
dispatcher.sender.dispatchEvent('someEvent');

sender.dispatchEvent() will just fire event from sender EventDispatcher, but MessagePortDispatcher.dispatchEvent() will actually send message to other side via postMessage().

Since MessagePortDispatcher passes data between origins, it can send only simple data(i.e. nothing can be sent by reference) that can be converted to JSON. Before sending event, it checks its data property value. If this value has method toJSON(), it will use it and send returned data as is. In other case the value will be converted to JSON string before being sent and converted back when received. When using toJSON() method its developer's responsibility to look for nested data objects and convert everything to transferable simple objects.

Project contains example in example folder, it shows how to use MessagePortDispatcher when communicating with frames.

API

MessagePortDispatcher constructor arguments

  • target:Object - Requred, target object, should have postMessage(), addEventListener(), removeEventListener() methods, asdescribed in MessagePort docs.
  • customPostMessageHandler:Function - will be used to call target.postMessage()
  • receiverEventPreprocessor:Function - Optional, allows pre-processing of events and their data before firing event.
  • senderEventPreprocessor:Function - Optional, , allows pre-processing of events and their data before passing them to postMessage or customPostMessageHandler.

MessagePortDispatcher instance members

  • targetOrigin:String
  • sender:EventDispatcher - fires outgoing events that are passed to postMessage()
  • receiver:EventDispatcher - fires incoming events received from other origin
  • target:Object - target object that is used for communication
  • dispatcherId:String - unique ID of current MessagePortDispatcher instance
  • addEventListener(eventType:String, listener:Function):void - method copied from receiver EventDispatcher for easier access
  • hasEventListener(eventType:String):Boolean - method copied from receiver EventDispatcher for easier access
  • removeEventListener(eventType:String, listener:Function):void - method copied from receiver EventDispatcher for easier access
  • removeAllEventListeners(eventType:String):void - method copied from receiver EventDispatcher for easier access
  • dispatchEvent(event:Object):void - does not fire event, it sends event to postMessage(). Can be used with two arguments:
  • - dispatchEvent(eventType:String, data?:Object):void

MessagePortTarget

A class that is used as a surrogate target for MessagePortDispatcher, it is useful when you have two objects for sending and receiving messages. For example, when you have an iframe with content from another origin and you can set iframe.contentWindow as sender object and own window as receiver. Sender object must contain postMessage() method and receiver object -- addEventListener() and removeEventListener() methods. Pass both sender and receiver into MessagePortTarget constructor, then it's instance can be provided for MessagePortDispatcher.

const frameDispatcher = new MessagePortDispatcher(new MessagePortTarget(iframeNode.contentWindow, window));

It also accepts lists of senders and receivers for mass sending and receiving.

const frameDispatcher = new MessagePortDispatcher(new MessagePortTarget([
  iframe1.contentWindow,
  iframe2.contentWindow,
  iframe3.contentWindow
  ], window));
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文