使用发布订阅模式封装处理postMessage浏览器通信

需求

统一规则、消息处理策略来维护消息通信,参考发布订阅模式实现on监听和emit触发,便于消息事件的跟踪及维护。

封装postMessage.js

class RPCMessageEvent {
  constructor (options) {
    this._currentTerminal = options.currentTerminal; // 当前终端
    this._targetTerminal = options.targetTerminal; // 远程终端
    this._targetOrigin = options.targetOrigin || '*'; // 域
    this._handlers = {}; // 响应函数

    const receiveMessage = pEvent => {
      const { event, args } = pEvent.data;
      const handlers = this._handlers[event] || [];
      handlers.length && handlers.forEach(handler => {
        handler(...(args || []));
      });
    };

    this._currentTerminal.addEventListener('message', receiveMessage, false);
  }

  on (event, handler) {
    const handle = this._handlers[event];
    this._handlers[event] = handle ? this._handlers[event].push(handler) : [handler];
  }

  emit (event, ...args) {
    this._targetTerminal.postMessage({ event, args }, this._targetOrigin);
  }

  off (event, handler) {
    if (!this._handlers[event]) { return; }
    if (!handler) {
      this._handlers[event] = [];
      return;
    }
    this._handlers[event] = this._handlers[event].filter(fn => handler !== fn);
  }
}

/**
 * @param {*} config 
 * 父域向子域iframe通知消息: rpcMessage(iframeDom).emit('eventName', data);  接收子域消息: rpcMessage(iframeDom).on('eventName', data=>{})
 * 子域iframe向父域通知消息: rpcMessage().emit('eventName', data); 接收父域消息: rpcMessage().on('eventName', data=>{})
 * 注意:页面销毁时需调用 off() 方法注销掉对应 rpcMessage
 */
const rpcMessage = (config)=>{
  let defaultConfig = {
    currentTerminal: window,
    targetTerminal: window.top,
    targetOrigin: '*'
  }
  if(config){
    if(Object.prototype.toString.call(config).toLowerCase() == "[object object]"){
      defaultConfig = Object.assign(defaultConfig, config)
    }else{
      defaultConfig.targetTerminal = config.contentWindow;
    }
  }
  return new RPCMessageEvent(defaultConfig)
}

export default rpcMessage

父域页面的接收和发送

<template>
  <div>
    <iframe ref="iframeBox" :height="iframeHeight" style="width: 100%;" src="http://localhost:8080/vue-plugin-hiprint/" frameborder="0"></iframe>
  </div>
</template>

<script lang='ts' setup>
import { ref, onMounted, onUnmounted } from 'vue';
import rpcMessage from '@/utils/postMessage.js'

let iframeBox = ref<any>(null);
let iframeHeight = ref(600)
let rpcMessageObj = null;

const sendData = (data)=>{
  setTimeout(() => {
    rpcMessageObj.emit('sendSelectDataSource', { aaa: '向子域发送消息' })
  }, 3000);
}

onMounted(()=>{
  iframeHeight.value = document.documentElement.clientHeight - 170; // 设置iframe高度
  iframeBox.value.onload = function (e) {
    rpcMessageObj = rpcMessage(iframeBox.value);
    rpcMessageObj.on('selectDataSource', data=>{
      console.log('接收子域消息', data)
      sendData(data)
    })
  };
})

onUnmounted(()=>{
  rpcMessageObj.off('selectDataSource')
})

</script>

子域页面的接收和发送

<template>
  <div>
  	<button @click="demo">触发按钮</button>
  </div>
</template>

<script lang='ts' setup>
import { ref, onMounted, onUnmounted } from 'vue';
import rpcMessage from '@/utils/postMessage.js'

let rpcMessageObj = rpcMessage()

const demo = ()=>{
  rpcMessageObj.emit('selectDataSource', { bbb: '向父域发送消息' })
}

onMounted(()=>{
  rpcMessageObj.on('sendSelectDataSource', data=>{
    console.log('接收父域消息', data)
  })
})

onUnmounted(()=>{
  rpcMessageObj.off('sendSelectDataSource')
})

</script>
!!!注意:页面销毁时必须调用 off() 注销掉对应 rpcMessage
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值