React Iframe 使用探索


作者后端經驗比較豐富,近期要做跨域跨前端框架的前端頁面展示,自然聯想到了 IFRAME 方法,細致了解下來發現它可以用來解決很多棘手問題,包括:

  • 跨域問題
  • Ajax 前進后退問題
  • 異步上傳問題
  • 跨框架問題

父頁面

基礎 React 框架

import React, { PureComponent } from 'react'; export default class Iframe extends PureComponent { render () { return ( <div> <h1>Parent</h1> <p>Send Message <button id="message_button" onClick={this.handleParentClick.bind(this)}>Hi child</button> </p> <span> Show Message </span> <div id='results'></div> </div> ); } } 

importexport 外部都是 React 基本框架,內部顯示了頁面布局:

 

 
Parent

Parent 提示當前部分是父頁面;
Send MessageHi child 按鈕用來向 iframe 傳遞消息,按鈕綁定了點擊事件 handleParentClick,后文會定義;
Show Messageresults div 用來展示 iframe 傳來的消息,后文會做處理。

 

iframe 相關事件

export default class Iframe extends PureComponent { receiveMessageFromIframe ( event ) { // React will send message started with setImmediate if (!event.data.startsWith('setImmediate')){ console.log("parent received", event.data); const results = document.getElementById('results'); results.innerHTML = event.data; } } componentDidMount () { // "message" name cannot be changed window.addEventListener("message", this.receiveMessageFromIframe, false); } handleParentClick = () => { //必須是iframe加載完成后才可以向子域發送數據 const childFrameObj = document.getElementById('myFrame'); childFrameObj.contentWindow.postMessage("This is parent", '*'); console.log("iframe height", childFrameObj.contentWindow.document.body.offsetHeight); childFrameObj.height = childFrameObj.contentWindow.document.body.offsetHeight + 60; // there will be some margin and stylistic height console.log("iframe window", childFrameObj.contentWindow); console.log("iframde document", childFrameObj.contentWindow.document); console.log("iframe html", childFrameObj.contentWindow.document.documentElement); } render () { ... } } 
  • handleParentClick 函數是處理 Hi child 按鈕點擊事件的:

    1. 先從 DOM 中獲得名字為 myFrame 的節點(后文 iframe 部分會展示)。
    2. 通過 contentWindow.postMessage 方法向 iframe 傳遞信息,參數有兩個,第一個是傳遞的信息內容(This is parent),另一個是 targetOrigin,即目標域,* 表示當前域,也可以寫成 http://baidu.com 等其他域名,但注意 iframe 的域必須和這個域名一致。
    3. 后面 2 行通過 contentWindow.document.body.offsetHeight 獲得 iframe 頁面高度,方便后續做自適應調整,+60 因為樣式上會產生其他的高度,這里是作為 buffer,實際使用中根據需要調整。
    4. 后面 3 行通過打印的方式展現常用可以獲取的 iframe 信息,包括 window, document, html 等。
  • componentDidMount 函數是在頁面加載后執行,React 的典型語法,這里增加了 parent 對 iframe 的事件監聽。

    window.addEventListener("message", this.receiveMessageFromIframe, false); 

    第一個參數不能修改,事件名稱是 message,第二個參數是 eventHandler,這里使用外面定義的 receiveMessageFromIframe 方法,第三個參數是默認值。

  • receiveMessageFromIframe 函數是事件監聽的處理函數,注意 React 也會使用 message 數據驅動,所以這里有過濾 message 以 setImmediate 開頭的信息,以捕獲 iframe 真正傳輸的數據。獲得數據后在展示區 results div 添加獲得的信息。

iframe 頁面

export default class Iframe extends PureComponent { render () { return ( <div> ... <iframe id="myFrame" width="100%" height={0} frameBorder={1} scrolling="no" srcDoc=" <h1>myFrame</h1> <p>Send Message: <button id='message_button'}>Hi parent</button></p> <span>Show Message</span> <div id='results'></div> <script> function receiveMessageFromParent ( event ) { let results = document.getElementById('results'); results.innerHTML += event.data + '<br>'; }; window.addEventListener('message', receiveMessageFromParent, false); let messageButton = document.getElementById('message_button'); /* console.log('msg button', messageButton); annoataion cannot use \/\/ */ messageButton.addEventListener('click', function (e) { console.log('iframe send msg'); console.log('parent', window.parent); console.log('top container', window.top); window.parent.postMessage('This is child', '*'); }, false); </script> " /> </div> ); } } 

原生 html 頁面

id 是 DOM 上節點名稱,上文有使用這里的 myFrame 來獲得節點進行操作;
width="100%" 是 iframe 寬度,可以是百分比或者數值,百分比可以自適應頁面;
frameBorder={1} 是 iframe 邊框是否展示,1 代表展示,0 代表不展示;
scrolling="no" 是滾動設置,yes 代表展示,no 代表不展示,auto 代表自動識別;
height={0} 是 iframe 高度,可以是百分比或者數值,這里設置為 0 代表無內容不展示,有內容后上文根據內容高度自適應展示;
srcDoc=<string> 是 iframe 的 DOM,可以使用原生 HTML 編寫;
src 是 iframe 的信息源。
srcDoc 內設置了 iframe 頁面:

  1. myFrame 提示當前是 iframe 頁面;
  2. Send MessageHi parent 是信息傳輸部分;
  3. Show Messageresults 用來展示從 parent 接受到的信息。

js 控制腳本

  • receiveMessageFromParent 函數用來控制從 parent 接受到信息后展示在展示區;
  • window.addEventListener 用來初始化事件監聽,和 parent 的事件監聽機制一樣,不贅述;
  • messageButton 獲取了當前組件的點擊按鈕;
  • messageButton.addEventListener 在點擊按鈕上綁定了點擊事件,注意點擊事件名稱不可修改,是 click,向 parent 傳遞消息使用 window.parent.postMessage,和 parent 的 postMessage 參數一致,不贅述。
  • 注意:iframe 使用的原生 html 頁面注釋不能使用 // 方法,只能使用 /* */ 完成。

整體代碼和效果

import React, { PureComponent } from 'react'; export default class Iframe extends PureComponent { receiveMessageFromIframe ( event ) { if (!event.data.startsWith('setImmediate')){ // React will send message started with setImmediate console.log("parent received", event.data); const results = document.getElementById('results'); results.innerHTML = event.data; } } componentDidMount () { window.addEventListener("message", this.receiveMessageFromIframe, false); // "message" name cannot be changed } handleParentClick = () => { //必須是iframe加載完成后才可以向子域發送數據 const childFrameObj = document.getElementById('myFrame'); childFrameObj.contentWindow.postMessage("This is parent", '*'); console.log("iframe height", childFrameObj.contentWindow.document.body.offsetHeight); childFrameObj.height = childFrameObj.contentWindow.document.body.offsetHeight + 60; // there will be some margin and stylistic height console.log("iframe window", childFrameObj.contentWindow); console.log("iframde document", childFrameObj.contentWindow.document); console.log("iframe html", childFrameObj.contentWindow.document.documentElement); } render () { return ( <div> <h1>Parent</h1> <p>Send Message <button id="message_button" onClick={this.handleParentClick.bind(this)}>Hi child</button></p> <span>Show Message </span> <div id='results'></div> <iframe id="myFrame" width="100%" height={0} frameBorder={1} scrolling="no" srcDoc=" <h1>myFrame</h1> <p>Send Message: <button id='message_button'}>Hi parent</button></p> <span>Show Message</span> <div id='results'></div> <script> function receiveMessageFromParent ( event ) { let results = document.getElementById('results'); results.innerHTML += event.data + '<br>'; }; window.addEventListener('message', receiveMessageFromParent, false); let messageButton = document.getElementById('message_button'); /* console.log('msg button', messageButton); annoataion cannot use \/\/ */ messageButton.addEventListener('click', function (e) { console.log('iframe send msg'); console.log('parent', window.parent); console.log('top container', window.top); window.parent.postMessage('This is child', '*'); }, false); </script> " /> </div> ); } } 
  • 初始效果,iframe 不展示:


     
    Parent
  • 點擊 Hi child 從 parent 傳遞信息給 iframe,iframe 自適應加載:
     
    image
  • 多次點擊 Hi child,iframe 自適應加載:
     
    image
  • 點擊 Hi parent 從 iframe 傳遞信息給 parent,展示信息:
     
    image


作者:Sisyphus235
鏈接:https://www.jianshu.com/p/e9239d820846
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

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



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