• 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)
      }
    

      

    将来的自己,会感谢现在不放弃的自己!
  • 相关阅读:
    1269 匈牙利游戏 2012年CCC加拿大高中生信息学奥赛
    2577 医院设置
    2488 绿豆蛙的归宿
    3315 时空跳跃者的魔法
    1079 回家
    1365 浴火银河星际跳跃
    1074 食物链 2001年NOI全国竞赛
    2596 售货员的难题
    wetask.cn领度任务全新试用体验
    多线程--生产者消费者--简单例子
  • 原文地址:https://www.cnblogs.com/TheYouth/p/15231702.html
Copyright © 2020-2023  润新知