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;width: 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)
  }

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM