/** * 跨域页面消息通信 *
* 作者:hugh zhuang * 邮箱:3378340995@qq.com * 日期:2018-07-02-下午3:29:34 * 版权:广州流辰信息技术有限公司 **/ import Storage from './storage' export const MESSAGE_TYPE = '__ibps_WEB_MESSAGER__' /** * 跨域页面消息通信类 * @class */ export default class Messager { /** * * @param {object} options 实例化参数选项 * @param {Window} [options.target] 通信目标,使用桥通讯时可以不传 * @param {string} [options.bridge] 目标桥页面url,如需要跨浏览器窗口传输数据,必须要设置 * @param {string} [options.origin] 自身的桥,目标可以通过桥联系到自己 * @param {function} [options.ready] 桥页面加载完成时回调函数 */ constructor(options) { const o = (this.options = { target: window, bridge: null, origin: null, ready: null, ...options }) /** * 通信目标对象 * @property {Window} target * @type {Window | *} */ this.target = o.target this.handlers = {} this.proxyBridgeHandler = this.bridgeHandler.bind(this) window.addEventListener('storage', this.proxyBridgeHandler) if (o.bridge) { this.buildBridge().then((el) => { this.target = el.contentWindow this.el = el o.ready && o.ready(this) }) } else { o.ready && o.ready(this) } } /** * 侦听消息 * @param {string} type 消息类型 * @param {Function} handler 处理函数 */ on(type, handler) { const listener = function (evt) { // message: {type:'XDH_WEB_MESSAGER', data:{type:'事件类型', data:{真正发送的数据},bridge:'' }} const message = evt.data || {} if (!message) return if (message.type === MESSAGE_TYPE && message.data.type === type) { handler(message.data.data, message.data.bridge) } } if (!this.handlers[type]) { this.handlers[type] = [] } this.handlers[type].push(listener) window.addEventListener('message', listener) } /** * 取消侦听 * @param {string} [type] 消息类型 * @param {Function} [handler] 处理函数 */ off(type, handler) { // 制定类型和事件句柄 if (type && handler) { const handlers = this.handlers[type] || [] handlers.forEach((h, index) => { if (handler === h) { handlers.splice(index, 1) window.removeEventListener('message', h) } }) // 制定事件类型 } else if (type) { const handlers = this.handlers[type] || [] handlers.forEach((h) => { window.removeEventListener('message', h) }) delete this.handlers[type] // 全不制定,全部取消侦听 } else { Object.keys(this.handlers).forEach((key) => { this.off(key) }) } } /** * 发送消息 * @param {string} [type] 消息类型 * @param {Object} [data] 发送数据 */ fire(type, data) { if (!this.target) return const message = { type: MESSAGE_TYPE, data: { type, data, bridge: this.options.origin } } // 桥转发时,数据包多一层 if (this.options.bridge) { const bridge = { type: MESSAGE_TYPE, data: message } this.target.postMessage(bridge, '*') } else { this.target.postMessage(message, '*') } } /** * 接收消息,只接收一次 * @param {string} [type] 消息类型 * @param {Function} [handler] 处理函数 */ once(type, handler) { this.on(type, () => { handler.apply(this, arguments) this.off(type, handler) }) } /** * 搭桥,创建iframe,加载桥页面 * @return {Promise