Vue 中嵌入 iframe 并进行双向通信的完整流程

Vue 中嵌入 iframe 并进行双向通信的完整流程经过反复测试 笔者发现 如果直接在 Vue 父组件的 created 方法中向 iframe 传递数据 此时 iframe 因为并没有被访问 导致无法传数据 无论是通过 id 还是 refs 都不能获取到这个 iframe 对象

欢迎大家来到IT世界,在知识的湖畔探索吧!

背景

Vue 应用中,需要使用 el-dialog 弹出一个 iframe 页面,该页面来源于其他项目,这就要解决 Vue 父页面和 iframe 子页面的两个通信问题:

  1. Vue 父页面向 iframe 子页面传递初始化数据
  2. 子页面的关闭按钮,需要通知父页面关闭 el-dialog

本文将整理 Vue 中嵌入 iframe 并进行双向通信的完整过程。

子页面直接调用父页面方法的跨域问题

理论上,如果 iframe 的 src 跟父页面同源,是可以直接用 window.parent.func 方法调用父类的 close 方法,完成 el-dialog 弹框关闭的。

但是,如果不同源,就会报错:

DOMException: Blocked a frame with origin "http://localhost:8085" from accessing a cross-origin frame.

欢迎大家来到IT世界,在知识的湖畔探索吧!

网上搜索到的解决办法是,使用 iframe 的 contentWindow.postMessage 方法传递数据给子页面。但是有一个问题,什么时候调用能得到真正的 iframe 对象呢?

父组件传递数据的时机

经过反复测试,笔者发现:如果直接在 Vue 父组件的 created 方法中向 iframe 传递数据,此时 iframe 因为并没有被访问,导致无法传数据,无论是通过 id 还是 $refs 都不能获取到这个 iframe 对象。

看这段网上搜到的通用方法:

欢迎大家来到IT世界,在知识的湖畔探索吧!<el-dialog :visible="showIFrame" :close-on-click-modal="false"
               @close="closeSelf" title="弹框配置" >
      <iframe id="myFrame"  ref="myframe" src="http://localhost:8085/myIFrame.html" 
      frameborder="0" scrolling="auto" marginheight="0" marginwidth="0" 
      width="100%" height="726px;">
      </iframe>
    </el-dialog>

此时,如果在 created 方法中传递数据:

created() { // 监听子组件的关闭事件消息 window.addEventListener('message', () => { this.closeSelf(); }, false); // 向子组件传递初始化数据 this.$refs.myframe.contentWindow.postMessage(data, '*'); // 取到的是 undefined const iframe = document.getElementById('myframe'); // 为 null iframe.contentWindow.postMessage(data,"*"); },

代码运行会报两种错误。

错误一,$refs 中没有该组件:

Vue 中嵌入 iframe 并进行双向通信的完整流程

错误一



欢迎大家来到IT世界,在知识的湖畔探索吧!

错误二,id 为 myframe 的元素为 null:

Vue 中嵌入 iframe 并进行双向通信的完整流程

错误二

解决办法:在 iframe 的 load 事件中向子页面传递数据,上面两种用法就不会报错了。

完整流程

父组件的 created 中监听子组件消息,调用关闭逻辑;同时,为 iframe 提供一个 @load=”loaded” 事件,在该事件中调用 postMessage 向子组件发送初始化数据。

首先,弹框 Vue 组件 PopupIframe.vue 代码如下:

欢迎大家来到IT世界,在知识的湖畔探索吧!<template>
  <div id="app">
    <el-dialog :visible="showIFrame" :close-on-click-modal="false"
               @close="closeSelf" title="Ifram配置">
      <iframe v-show="src!==''"  
      id="myframe" 
      @load="loaded" 
      ref="myframe" 
      :src="src" frameborder="0" scrolling="auto" marginheight="0" marginwidth="0" width="100%" height="726px;"></iframe>
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: 'PopupIframe',
  props: ['showIFrame'],
  data() {
    return {
      src: '',
      data: {
      },
    };
  },
  created() {
    // 设置 src
    this.src = 'http://localhost:8087/myIfram.html";
    // 监听子组件的关闭事件
    window.addEventListener('message', () => {
      this.closeSelf();
    }, false);
  },
  methods: {
    loaded() {
      // 只有在 iframe 加载时传递数据给子组件,$refs 才是非空的
      this.$refs.myframe.contentWindow.postMessage({
        type: 'myData',
        data: this.data,
      }, '*');
    },
    closeSelf() { // 关闭当前弹框
      this.$emit('closeIframe');
    },
  },
};
</script>

第二步,iframe 子页面添加监听数据的方法:

window.addEventListener('message', (e) => { console.log(e.data); if (e.data.type === 'myData') { // TODO 使用父组件传递的初始化数据 } });

第三步,iframe 的页面的关闭按钮向父组件发送消息,通知关闭:

欢迎大家来到IT世界,在知识的湖畔探索吧!window.parent.postMessage('close', '*');

PopupIframe.vue 被其他组件引用就可以了。

postMessage 数据类型

测试发现,this.$refs.myframe.contentWindow.postMessage 向 iframe 子组件发送数据后,子组件收到的数据除了第一步定义的数据外,还有其他数据,它的监听方法里面会执行两次:

Vue 中嵌入 iframe 并进行双向通信的完整流程

postMessage 的内容

这说明,框架也向子组件发送了一些数据,类型为打包的告警数据。

因此,父组件传递数据时,也可以按照这个格式添加一个 type 标识我们的数据,前面第二步操作中,子组件使用时再根据它处理自己需要的数据。

总结:本文的核心知识点是 iframe 的 load 事件,要想顺利传递数据给 iframe ,必须在这里调用才能得到 iframe 对象。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/94235.html

(0)
上一篇 5小时前
下一篇 5小时前

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信