iframe通信——postMessage

一、简介

postMessage是HTML5中新引入的API,它可以实现跨窗口以及跨域的通信。postMessage类似与Ajax但是它不受同源策略的限制并且通信双方都是客户端。本文的目的就是验证下这种跨页面通信方法的使用流程。

二、具体准备

1、首先我们先写一个页面a,页面嵌套一个iframe标签,iframe的地址为b页面
<div id="app" class="page-box">
  main-page
  <iframe id="iframe" src="http://127.0.0.1:5500/src/html-pages2/iframe-page.html" 
    frameborder="1"></iframe>
</div>
2、编写a页面发送消息的接口

window.postMessage(message, targetOrigin,[transfer]);

message: 要发送的数据。这个参数可以是任何可以序列化成字符串的JavaScript值,包括字符串、数字、布尔值以及对象(对象会被自动转换为JSON字符串)。
targetOrigin: 一个字符串,指定了接收消息窗口的源(origin)。这个参数是必需的,用来限制哪些源可以接收到消息。如果设置为’*',则表示任何源都可以接收消息,但这不推荐,因为它可能会带来安全风险。

transMessage() {
  let otherWindow = document.getElementById('iframe').contentWindow
  let message = '来自主页面的消息'
  let msgJson = JSON.stringify(message)
  otherWindow.postMessage(msgJson, "http://127.0.0.1:5500/src/html-pages2/iframe-page.html")
}

mounted() {
  window.addEventListener('message', (event) => {
    console.log(event.data)
  }, false)
  setTimeout(() => {
    this.transMessage()
  }, 2000)
},
3、b页面 iframe页面,监听message
mounted() {
  window.addEventListener('message', this.handleMessage, false)
},

handleMessage(event) {
  console.log('message', event.data)
  let message = '已收到'
  let msgStr = JSON.stringify(message)
  parent.postMessage(msgStr, 'http://127.0.0.1:5500/src//html-pages2/index-page.html')
} // parent可以获取父窗口window

window.parent 返回父窗口,如果窗口本身是顶层窗口,parent属性返回的是对自身的引用
window.top 返回顶层窗口,即浏览器窗口,如果窗口本身就是顶层窗口,top属性返回的是对自身的引用
window.self 是对当前窗口自身的引用。它和window属性是等价的。

三、实现代码

全部代码

a页面:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <meta name="referrer" content="origin">
    <meta name="viewport" content="width=device-width, viewport-fit=cover, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <meta name="Cache-Control" content="no-cache, no-store, must-revalidate">
    <script type="text/javascript" src="https://cdn.bootcss.com/vConsole/3.3.0/vconsole.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script>
    <script src="./js/flexible.js"></script>
    <style>
      .page-box {
        box-sizing: border-box;
        /* background-color: #f2f6ff; */
        background-color: #fff;
        padding: .36rem;
      }
    </style>
  </head>
  <body>
    <div id="app" class="page-box">
      main-page
      <iframe id="iframe" src="http://127.0.0.1:5500/html-pages2/iframe-page.html" frameborder="1"></iframe>
    </div>
    <script>
      let vue = new Vue({
        el: '#app',
        data() {
          return {
            order: {}
          }
        },
        mounted() {
          window.addEventListener('message', (event) => {
            console.log(event.data)
          }, false)
          setTimeout(() => {
            this.transMessage()
          }, 2000)
        },
        methods: {
          transMessage() {
            let otherWindow = document.getElementById('iframe').contentWindow
            let message = '来自主页面的消息'
            let msgJson = JSON.stringify(message)
            otherWindow.postMessage(msgJson, "http://127.0.0.1:5500/html-pages2/iframe-page.html")
          }
        }
      })
    </script>
  </body>
</html>

b页面:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <meta name="referrer" content="origin">
    <meta name="viewport" content="width=device-width, viewport-fit=cover, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <meta name="Cache-Control" content="no-cache, no-store, must-revalidate">
    <script type="text/javascript" src="https://cdn.bootcss.com/vConsole/3.3.0/vconsole.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script>
    <script src="./js/flexible.js"></script>
    <style>
      .page-box {
        box-sizing: border-box;
        /* background-color: #f2f6ff; */
        background-color: #fff;
        padding: .36rem;
      }
    </style>
  </head>
  <body>
    <div id="app" class="page-box">
      iframe-page
    </div>
    <script>
      let vue = new Vue({
        el: '#app',
        data() {
          return {
            order: {}
          }
        },
        mounted() {
          window.addEventListener('message', this.handleMessage, false)
        },
        methods: {
          handleMessage(event) {
            console.log('message', event.data)
            let message = '已收到'
            let msgStr = JSON.stringify(message)
            parent.postMessage(msgStr, 'http://127.0.0.1:5500/html-pages2/index-page.html')
          }
        }
      })
    </script>
  </body>
</html>

页面效果:

GIF 2024-6-25 0-04-48.gif

四、注意事项

因为a页面加载时机比iframe中的b页面加载时机快,所以b页面中的message监听会慢于父页面mounted中的发送消息,这样会接受消息失败,所以加了setTimeout函数来延时发送消息。

  • 34
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值