iframe 子父传值封装 postmessage封装2.0

1.0在使用过程中存在很多问题
1.同时发送多个postMessage请求的时候,回调属于异步执行,会不知道谁返回的
2.子页面同名订阅时,后面的会覆盖前面队列中的方法

下面是2.0的封装及示例,请查收
这次是在vue环境中调试的

postmessage.js

/**
 *  @author Saryz
 *  iframe solution
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
      (global = global || self, global.postmessage = factory())
}(this, function () {
  const commonMethod = 'haha'
  // 管道集合
  const queueMap = new Map()
  // 全局监听
  console.log('【siframe】【addEventListener】当前页面:', location.href)
  let postMessageListenerFlag = false
  if (!postMessageListenerFlag) {
    window.addEventListener('message', function (event) {
      postMessageListenerFlag = true
      // 事件过滤
      if (event.data.type !== 'S-IFRAME') return
      // 来源页面地址
      const sourceUrl = event.data.sourceUrl
      console.log('【siframe】【addEventListenerCallBack】', event)
      // 执行集合中方法
      queueMap.get(event.data.method + sourceUrl).fn(event.data.data)
    })
  }

  /**
   * 给子页面传值
   * @param {*} iframe
   * @param {*} methodName
   * @param {*} data
   */
  function postToIframe (iframe, methodName, data, fn) {
    // 目标iframe地址 通常指子页面地址
    const iframeUrl = iframe.getAttribute('src') || iframe
    console.log('【siframe】【postToIframe】from', location.href, 'to', iframeUrl)
    iframe.contentWindow.postMessage({
      method: methodName || commonMethod,
      data: data,
      type: 'S-IFRAME',
      sourceUrl: iframe.src
    }, '*')
    // 注册回调方法
    fn && listen(methodName, fn, iframe)
  }

  /**
   * 给父级页面传值
   * @param {*} methodName
   * @param {*} data
   */
  function postToParent (methodName, data, fn) {
    console.log('【siframe】【postToParent】from', location.href, 'to parent')
    window.parent.postMessage({
      method: methodName || commonMethod,
      data: data,
      type: 'S-IFRAME',
      sourceUrl: window.location.href
    }, '*')
    // 注册回调方法
    fn && listen(methodName, fn)
  }

  /**
   * 注册监听事件
   * @param methodName
   * @param fn
   * @param iframe
   */
  function listen (methodName, fn, iframe) {
    const hostUrl = iframe ? iframe.src : location.href
    queueMap.set(methodName + hostUrl, { fn })
    console.log('【siframe】【listen】【hostUrl】', hostUrl, '【queueMap】', queueMap)
  }

  /**
   * 发送消息
   * @param iframe
   * @param methodName
   * @param data
   * @param fn
   */
  function trigger (iframe, methodName, data, fn) {
    if (iframe) {
      postToIframe(iframe, methodName, data, fn)
    } else {
      postToParent(methodName, data, fn)
    }
  }

  return {
    listen,
    trigger
  }
}))



parent.vue

<template>
  <div class="page">
    <p>Parent
      <button @click="checkChildForm">checkChildForm</button>
    </p>
    <div class="iframe_box" v-for="(item,index) in iframesList" :key="item.id">
      <iframe :ref="'iframe'+index" :src="item.path" frameborder="0" :name="'name'+item.id"></iframe>
    </div>
  </div>
</template>

<script>
export default {
  name: 'parent',
  data () {
    return {
      iframesList: [
        {
          id: 1,
          path: 'http://192.168.43.181:8081/#/child1'
        },
        {
          id: 2,
          path: 'http://192.168.43.181:8081/#/child2'
        }
      ],
      form: {
        name: 'parent',
        sex: '1',
        brithday: '20200202'
      }
    }
  },
  created () {

  },
  mounted () {
    const iframeDom = this.$refs
    const that = this
    Object.keys(iframeDom).forEach(key => {
      postmessage.listen('getPersonInfo', function (data) {
        postmessage.trigger(iframeDom[key][0], 'getPersonInfo', that.form)
      }, iframeDom[key][0])
    })
  },
  methods: {
    checkChildForm () {
      console.log('parent发消息')
      Object.keys(this.$refs).forEach(key => {
        console.log('postmessage', key)
        postmessage.trigger(this.$refs[key][0], 'checkChildForm', { p: 'parent checkForm' }, (data) => {
          console.log(key + 'parent postmessage trigger checkChildForm callback', data)
        })
      })
    }
  }
}
</script>

<style lang="scss" type="text/scss" scoped>
.page {
  padding: 20px;
  width: 80vw;
  height: 80vh;
  background: #2c3e50;
  position: fixed;
  left: 50%;
  top: 50%;
  margin-left: -40vw;
  margin-top: -40vh;
  color: #fff;
}

iframe {
  width: 200px;
  height: 200px;
  background: #fff;
}

.iframe_box {
  margin-bottom: 10px;
}
</style>

child1.vue

<template>
  <div>
    <p>child1</p>
    <button @click="getPersonInfo">getPersonInfo</button>
  </div>
</template>

<script>
export default {
  name: 'child1',
  data () {
    return {}
  },
  created () {
    const form = { name: 'child1' }
    const getFormKey = 'checkChildForm'
    postmessage.listen(getFormKey, function (data) {
      console.log('child1 checkChildForm方法', '当前收件人' + location.href, '收到了消息', data)
      postmessage.trigger(null, getFormKey, form)
    })
  },
  methods: {
    getPersonInfo () {
      console.log('child1 getPersonInfo========>')
      postmessage.trigger(null, 'getPersonInfo', { name: 'child1' }, result => {
        console.log('我是' + location.href, '我拿到了从父级得到的数据Person', result)
      })
    }
  }
}
</script>

<style lang="scss" type="text/scss" scoped>

</style>

child2.vue

<template>
  <div>
    <p>child2</p>
    <button @click="getPersonInfo">getPersonInfo</button>
  </div>
</template>

<script>
export default {
  name: 'child2',
  data () {
    return {}
  },
  created () {
    const form = { name: 'child2' }
    const getFormKey = 'checkChildForm'
    postmessage.listen(getFormKey, function (data) {
      console.log('child2 checkChildForm方法', '当前收件人' + location.href, '收到了消息', data)
      postmessage.trigger(null, getFormKey, form)
    })
  },
  methods: {
    getPersonInfo () {
      console.log('child2 getPersonInfo========>')
      postmessage.trigger(null, 'getPersonInfo', { name: 'child2' }, result => {
        console.log('我是' + location.href, '我拿到了从父级得到的数据Person', result)
      })
    }
  }
}
</script>

<style lang="scss" type="text/scss" scoped>

</style>

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Saryz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值