Iframe嵌入跨域頁面高度自適應實現詳解

zhangjunfun發表於2020-12-02

專案中要在頁面中嵌入通過富文字編輯器編輯的html內容子頁面,預想可通過兩種方式實現:

方式一:是將內容子頁面的html程式碼通過vue v-html方式渲染到主頁面的div下;

方式二:通過在主頁面嵌入iframe頁面實現;

兩種方式都進行了驗證,並且都遇到問題:

方式一問題:可以渲染出子頁面html內容,但是丟失css樣式,引入ckeditor的標準樣式css後,絕大部分樣式問題解決,但通過標籤選擇器指定的樣式會受主頁面樣式的干擾,導致子頁面內容在瀏覽器上無法還原實際顯示效果;

方式二問題:iframe方式可以很輕易的載入出子頁面內容,但由於子頁面與主頁面之間跨域,所以主頁面無法獲取到iframe子頁面的document,從而無法獲取子頁面的實際高度,顯示效果無法達到預期。

經過比較果斷選取方式二來解決,那麼如何解決跨域獲取iframe子頁面高度,並實現iframe自適應子頁面高度的問題呢?

最終採用iframe子頁面通過postMessage方式解決問題,具體如下:

1)子頁面onload完成後通過postMessage方式將實際頁面高度通知給父頁面;

      var ele_height = element.offsetHeight;
      console.log("Size: " + ele_height);
      if(this.frameMode) {
        let _resizeMsgObj = {
          type: "resize",
          data: {
            height: ele_height
          }
        };
        top.postMessage(JSON.stringify(_resizeMsgObj), '*');

2)父頁面監聽訊息,並在接收到訊息後調整iframe高度;

html程式碼:

<div class="com_right_content" style="height: auto;">
    <iframe style="width: 100%;height:800px;"
                  :src="detailPreviewMediaInfo.webviewurl"
                  frameborder="0"
                  scrolling="no"
                  id="contentIframe">
    </iframe>
</div>

js程式碼:

window.addEventListener('message', function(event){
          console.log(`received message: `, event.origin, event.data)
          let msgdataStr = String(event.data)
          if(msgdataStr.indexOf("resize") != -1){
            console.log(`received iframe resize message: `, event, event.data)
            let msgdata = JSON.parse(msgdataStr)
            document.getElementById('contentIframe').style.height = msgdata.data.height + 'px'
          }

        }, false);

補充說明:

由於父頁面不知道子頁面的高度,先將iframe高度設定為0px,接收到子頁面訊息後再將iframe高度設定為實際高度,發現iframe載入需要較長時間,原因是子頁面onload事件是在整個頁面全部載入完成後才觸發,包括頁面所有js、css、圖片檔案的載入,但圖片載入需要較長時間,所以iframe載入時間過長,影響使用者體驗,但在圖片載入完之前子頁面的高度又可能不準確,因此在父頁面在初始時給iframe設定一個高於一屏的高度,可以較好的解決使用者體驗問題。

相關文章