前端技巧——iframe + postMessage进行页面通信

应用场景

我们知道iframe标签可以将另外一个页面嵌入到该标签当中,相当于开启一个画中画。这个一般就用来嵌入一个统一的登陆验证功能。那么这样就会存在一个问题,我们需要嵌入的子页面能够和当前的主页面进行通信,所以我们就需要使用某种方法来实现不同源之间的页面的通信功能,所以我们需要postMessage

iframe标签文档:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/iframe

postMessage文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

环境说明

我们在vue3的环境下来实现该功能,你可以使用如下命令来实现创建一个vue3模板

pnpm create vue@latest

功能介绍

我们需要实现父页面对子页面 发送消息与接收消息+子页面对父页面 发送消息与接收消息

这四个功能完成之后随便怎么嵌入都没问题

父页面对子页面发送消息

我们首先在父项目定义一个iframe标签,书写好html

html 复制代码
<iframe id="iframe" src="http://localhost:5174" frameborder="0"></iframe>

后面我们参考postMessage的文档,可以知道,他需要一个窗口对象才能使用,恰巧我们的iframe提供了contentWindow属性来获取这样一个对象,又为了防止网络出现问题导致代码执行后子页面还没有出来,我们可以使用onload回调后在iframe设置等待子页面加载后执行

javascript 复制代码
// 发送消息给子页面
  const iframe = document.getElementById('iframe')
  console.log('xxxxx', iframe)
  iframe.onload = () => {
    iframe.contentWindow.postMessage({ data: '你好', type: 'DIY' }, 'http://localhost:5174/')
  }

这里我们统一使用了我们自己的数据结构,来区分哪些消息是我们自主发出的

子页面接受父页面传来的消息

javascript 复制代码
window.addEventListener(
  'message',
  (e) => {
    // 父窗口发送的消息
    if (e.origin === 'http://localhost:5173' && e.data.type === 'DIY') {
      console.log('xxxxx', e.origin, e.source, e.data)
    }
  },
  false
)

子页面对父页面发送消息

javascript 复制代码
window.parent.postMessage({ data: '你好', type: 'DIY' }, 'http://localhost:5173')

父页面接受子页面传来的消息

javascript 复制代码
  // 给父页面添加监听获取子页面发送来的消息
  window.addEventListener('message', (event) => {
    if (event.origin === 'http://localhost:5174' && event?.data?.type === 'DIY') {
      console.log('event', event.origin, event.source, event.data)
    }
  })

有了上面这些功能,相信你也可以自己实现一个统一登陆平台了,加油吧,下面是代码

代码

父页面代码

javascript 复制代码
<template>
  <div class="welcome">
    <div class="title">这里是欢迎标签</div>
    <iframe id="iframe" src="http://localhost:5174" frameborder="0"></iframe>
  </div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue'
onMounted(() => {
  // 发送消息给子页面
  const iframe = document.getElementById('iframe')
  console.log('xxxxx', iframe)
  iframe.onload = () => {
    iframe.contentWindow.postMessage({ data: '你好', type: 'DIY' }, 'http://localhost:5174/')
  }
  // 给父页面添加监听获取子页面发送来的消息
  window.addEventListener('message', (event) => {
    if (event.origin === 'http://localhost:5174' && event?.data?.type === 'DIY') {
      console.log('event', event.origin, event.source, event.data)
    }
  })
})
</script>

子页面代码

javascript 复制代码
<template>
  <div class="content">
    <div>这是子页面</div>
    <input type="text" v-model="inputText" />
    <button @click="sub">发送</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const sub = () => {
  console.log('打印信息')
  window.parent.postMessage({ data: '你好', type: 'DIY' }, 'http://localhost:5173')
}

const inputText = ref('')
window.addEventListener(
  'message',
  (e) => {
    // 父窗口发送的消息
    if (e.origin === 'http://localhost:5173' && e.data.type === 'DIY') {
      console.log('xxxxx', e.origin, e.source, e.data)
    }
  },
  false
)
</script>

<style scoped>
header {
  line-height: 1.5;
  max-height: 100vh;
}

.logo {
  display: block;
  margin: 0 auto 2rem;
}

nav {
  width: 100%;
  font-size: 12px;
  text-align: center;
  margin-top: 2rem;
}

nav a.router-link-exact-active {
  color: var(--color-text);
}

nav a.router-link-exact-active:hover {
  background-color: transparent;
}

nav a {
  display: inline-block;
  padding: 0 1rem;
  border-left: 1px solid var(--color-border);
}

nav a:first-of-type {
  border: 0;
}

@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }

  .logo {
    margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }

  nav {
    text-align: left;
    margin-left: -1rem;
    font-size: 1rem;

    padding: 1rem 0;
    margin-top: 1rem;
  }
}
</style>
相关推荐
Neweee3 分钟前
JavaScript进阶内容详解
前端
大鸡爪4 分钟前
Vue3 组件库实战(五):Icon 图标组件的设计与实现
前端·vue.js
bluceli5 分钟前
前端测试实战指南:构建高质量代码的完整体系
前端·测试
行走的陀螺仪5 分钟前
前端公共库开发保姆级路线:从0到1复刻VueUse官方级架构(pnpm+Turbo+VitePress)
前端·架构
顽固_倔强5 分钟前
深入理解 Vue3 数据绑定实现原理
前端·面试
前端付豪5 分钟前
组件拆分重构 App.vue
前端·架构·代码规范
Wect6 分钟前
React 更新触发原理详解
前端·react.js·面试
cxxcode6 分钟前
Web 帧渲染与 DOM 准备
前端
光影少年7 分钟前
React Hooks的理解?常用的有哪些?
前端·react.js·掘金·金石计划
大鸡爪7 分钟前
Vue3 组件库实战(七):从本地到 NPM:版本管理与自动化发布指南(下)
前端·vue.js