iframe 详解-在vue中使用iframe/iframe在vue中使用

一、什么是iframe?

  1. 使用 iframe + postMessage 实现跨域通信

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

  在实际项目开发中可能会碰到在 aa.com 页面中嵌套 bb.com 页面,这时第一反应是使用 iframe,但是产品又提出在 aa.com 中操作,bb.com 中进行显示,或者相反。

      postMessage语法:

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

otherWindow:其他窗口的一个引用(在这里我使用了iframe的contentWindow属性)
message:将要发送到其他window的数据
targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项
不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,
必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。
不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。 transfer:可选参数

二、遇到的问题

  1. postMessage发送消息跨域问题

   // 不限制域名就用*,否则就是具体域名,这样可以解决跨域问题
        iframe.postMessage(dict, '*')

  2. postMessage传递数据的格式

data: {// 最外面这个是postMeaage自带的,下面才是自己定义的数据格式,也可以不要内层的data:
  data: {
    responseCode: '000000'
    body: {
	id: ""
	name: "模板1"
    }
  }
  type: "TYPE"
}

三、实例代码如下:下面的是iframe实用的例子,应用的是postMessage发送的消息,本例是父组件往子组件传递数据

注意:如果使用postMessage发送消息时,如果不使用按钮触发的话,有可能发送失败,所以下面例子针对此情景做了发送消息失败的处理方案

<template>
    <div class="main-info">
        <iframe
         ref="iframe"
         id="iframe"
         frameborder="0"
         :src="iframeSrc"
         style="min-height: 800px; 100%"
        >
        </iframe>
    </div>
</template>
// 定义数据 
data () {
    return {
      iframeSrc: '',
      iframe: '',
      isReceiveMsg: false, // 是否收到消息,收到消息停止计时器,不再发送postMessage消息
      actionNum: 5, // 最多执行5次
      timer: null,// 定时器
    }
  },
  created() {
    this.iframeSrc = `http://www.baidu.com`
    // 监听收到消息
    window.addEventListener('message', this.handleMessageEvent)
  },
mounted () {
    const self = this
    this.$nextTick(() => {
      const iframe = document.getElementById('iframe')
      if (iframe.attachEvent) { // 适配IE
        iframe.attachEvent('onload', function () {
          self.clickIframe()
          setTimeout(() => {
            self.handlePostMessageFail()
          }, 1000)
        })
      } else {
        iframe.onload = function () {
           // 坑一,postMessage发送通知时,可能对方的页面还没有加载完成导致发送失败
            self.clickIframe()
            setTimeout(() => { 
              self.handlePostMessageFail() 
            }, 1000) } } }) 
     }
},
  methods: {
    handleMessageEvent(event) {
      if (event.data && event.data.data) {
        const data = event.data.data
        const body = data.body || ''
        if (parseInt(data.responseCode) === 0) {
          // 成功返回
          setTimeout(() => {
            this.$router.push({ name: this.backPath })
          }, 500)
        } else if (parseInt(data.responseCode) === 2) {
          // 收到消息
          console.log('-------已收到消息', data)
          this.isReceiveMsg = true
        }
      }
    },
    clickIframe() {
      const iframe =
        document.getElementById('iframe') &&
        document.getElementById('iframe').contentWindow
      if (!iframe) return
        const list = []
        list.push(this.processData)
        const dict = {
          processList: list
        }
        // 不限制域名就用*,否则就是具体域名
        iframe.postMessage(dict, '*')
      },
// 其中clickIframe里是处理iframe的src的
// 处理失败机制
  // postMessage消息发送失败机制,上面定义执行5次,第隔1.5秒,之前设置3次,间隔一秒,还是有失败的,所以这里采用这个
    handlePostMessageFail () {
      this.timer = setInterval(() => {
        if (!this.isReceiveMsg) {
          if (this.actionNum <= 0) {
            clearInterval(this.timer)
            this.timer = null
            this.isReceiveMsg = true
            return
          }
          this.clickIframe()
          this.actionNum--
        } else {
          clearInterval(this.timer)
          this.timer = null
          this.isReceiveMsg = true
        }
      }, 1500)
    },
 // 记得离开页面时,要消毁掉
  destroyed() {
    window.removeEventListener('message', this.handleMessageEvent)
  }

  

将来的自己,会感谢现在不放弃的自己!
原文地址:https://www.cnblogs.com/TheYouth/p/15231702.html