這周碰到一個讓人頭疼的需求:要在個人web項目中嵌入另外一個第三方web項目。第一時間想到的就是用iframe
了,但問題來了,我和第三方web項目是有交互的,這就違反同源策略了,處理跨域問題是最讓人頭疼的事之一。javascript
需求是這樣的,在個人頁面點擊一些按鈕,要實時反饋到iframe
子頁面,子頁面再進行響應。html
當時腦子裏第一時間想到的解決方案是:用NGINX
把兩個項目代理到同一域名下。但這樣彷佛有點小題大作了,有沒有更方便快捷的方法呢?java
在window
對象下有個postMessage
方法,是專門用來解決跨域通訊問題的。git
關於postMessage的詳細介紹請戳這裏,不過MDN的文檔太詳細了,致使有些同窗看完仍是一臉懵逼,下面咱們就來看看怎麼用postMessage
實現iframe跨域通訊,當你會用了以後再回去看文檔,感受是徹底不一樣的。github
首先咱們模擬場景,假設有兩個不一樣源的頁面,iframePage.html
是index.html
的子頁面:web
<!-- index.html -->
<body style="border:5px solid #333;">
<h1>this is index</h1>
<iframe src="./iframePage.html" id='myframe'></iframe>
</body>複製代碼
<!-- iframePage -->
<body style="border:5px solid #333;">
<h1>this is iframePage</h1>
</body>複製代碼
如今這兩個iframe是沒法通訊,由於它們是不一樣源的(假設存在跨域問題),這時候就要用到postMessage
了。跨域
咱們先試着從父頁面向子頁面發送一條消息:微信
// idnex.html
//獲取iframe元素
iFrame = document.getElementById('myframe')
//iframe加載完畢後再發送消息,不然子頁面接收不到message
iFrame.onload = function(){
//iframe加載完當即發送一條消息
iFrame.contentWindow.postMessage('MessageFromIndex1','*');
}複製代碼
咱們知道postMessage
是掛載在window
對象上的,因此等iframe
加載完畢後,用iFrame.contentWindow
獲取到iframe
的window
對象,而後調用postMessage
方法,至關於給子頁面發送了一條消息。函數
postMessage
方法第一個參數是要發送的數據,能夠是任何原始類型的數據。post
Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3)以前,第一個參數必須是一個字符串。
postMessage
方法第二個參數能夠設置要發送到哪一個url,若是當前子頁面的url和設置的不一致,則會發送失敗,咱們設置爲*
,表明全部url都容許發送。
postMessage
方法還有第三個參數,屬於高級用法,這裏不作討論,能夠稍後去MDN瞭解。
消息發送到iframePage.html
,咱們來接收message:
// iframePage.html
//回調函數
function receiveMessageFromIndex ( event ) {
console.log( 'receiveMessageFromIndex', event )
}
//監聽message事件
window.addEventListener("message", receiveMessageFromIndex, false);複製代碼
咱們只須要在子頁面監聽message
事件,而且設置好回調函數便可,來看看打印出來的event
:
event
對象中的data
屬性存放着咱們從父頁面傳過來的數據,就這麼簡單!
讓咱們再試試從子頁面發送數據給父頁面:
// iframePage.html
//給父頁面發送消息,data爲對象
parent.postMessage( {msg: 'MessageFromIframePage'}, '*');複製代碼
父頁面接收數據:
//index.html
//回調函數
function receiveMessageFromIframePage (event) {
console.log('receiveMessageFromIframePage', event)
}
//監聽message事件
window.addEventListener("message", receiveMessageFromIframePage, false);複製代碼
我看看到,的確能夠傳輸不一樣的數據,此時data
爲一個對象:
你們能夠到postMessage-demo把代碼clone下來運行試試看。
喜歡本文的朋友能夠關注個人微信公衆號,不按期推送一些好文。
本文出自Rockjins Blog,轉載請與做者聯繫。不然將追究法律責任。