postMessage 主頁、iframe頁可互相傳值

postMessage 主頁、iframe頁可互相傳值

前端的一個困擾:管不到 iframe

前端有一件麻煩事就是iframe這件事,比方:頁面裡有個iframe,主頁要抓iframe裡的東西,或是iframe想傳值給主頁。

如果主頁跟iframe頁同網域,JS還可以由主頁抓到iframe頁,但兩頁不同網域的話就不行。

Augustus以前有遇過一個需求,有2個頁面,都是公司的,但網域不同,在A頁面要iframe B頁面,還要無違合的放進頁面裡,高度要剛好,不能出現scroll bar,也不能被截掉。

但在不同網域下,是無法去抓iframe的值的,不論是高度或是裡面的參數什麼的。

放個廣告賺點養主機的$$,謝謝

這時,就需要postMessage這個好物,它可以讓2個不同網域的頁面互相傳值,因此就只要B頁面load完時,傳B頁面本身的高度給A頁,讓A頁改變iframe的height就行。

Google、Facebook也是這樣傳值的

監聽一下postMessage事件並console.log,會看見Google、Facebook也是這樣在傳值。

Google廣告或是FB的讚按鈕,它們iframe到其它網站時,網域一定跟Google、FB的不同,而iframe又無法抓到外面頁面的值,或是外面頁面想傳值給iframe頁時怎麼辦?這時就要用postMessage。

本篇筆記要記錄的就是A、B頁面iframe的情況下,A傳給B,或B傳給A的問題,該怎麼用postMessage來解決。


postMessage基本使用

postMessage是傳遞參數的功能,分為2部份:傳值、接值。

傳值,就是A把參數傳給B,這是postMessage。

接值,就是當B收到A傳來的message後要做什麼,這是addEventListener message。


傳值

傳值就是用postMessage,code如下:

目標視窗.postMessage(要傳的參數, 目標的網域);

要傳的參數:就是要傳的參數(有夠直白XD),比方想傳高度,那就是寫高度。也可以寫一個陣列裡面包多個值。

放個廣告賺點養主機的$$,謝謝

目標的網域:postMessage可以指定要傳給哪一個網域,在接值時也可以指定專收哪個網域來的message。本篇主頁用 https://mother.tw,iframe頁用 https://iframe.tw

目標視窗:有三種情況,要寫的值不一樣,如下

主頁傳值給iframe

目標視窗就是iframe:

var iframe = document.getElementById('iframe').contentWindow;
iframe.postMessage('message', 'https://iframe.tw');

iframe傳值給主頁

目標視窗就是parent:

parent.postMessage('message', 'https://mother.tw');

主頁用window.open的方式開了一個視窗

這部份Augustus還沒遇過實際的需求,放上MDN的範例:

var popup = window.open(...popup details...);
popup.postMessage("hello there!", "http://example.org");

接值

監聽message事件就行了:

// 接到 message 要做什麼事的 function
function receiveMessage(e) {
  // 來源網址(e.origin)不是指定的網域時
  if(e.origin !== 'https://xxxxxxx.tw') {
    alert('資料來源錯誤');
    return false;
  }
  // 來源網址是指定的網域時
  else {
    // 拿傳來的參數(e.data)
    const data = e.data;
  }
}
 
 // 監聽 message 事件
 window.addEventListener('message', receiveMessage, false);

在傳值那段的目標的網域有寫,傳值、接值都可以指定網域,MDN上是寫可以用萬用「*」代表不限網域,但那就是連外星人都可以傳值到頁面上,所以建議是寫上指定網域。

function裡面用 e.origin 來確認傳訊息來的網域是不是你要接收的網域。

比方iframe要接來自 https://mother.tw 的 message,但實際頁面上可能還有Google廣告、FB讚鈕的message在那傳個滿天飛,總不能每次有message來就不斷在執行function,因此才要先寫 if(e.origin !== 'https://xxxxxxx.tw'){} else { // 做某件事 } 來確保來源網域是 mother.tw。


原始碼、Demo

Augustus寫了一個頁面Demo,裡面有2個範例:

  1. iframe頁傳訊息給母頁:iframe的高度就是iframe頁面本身的高度,無縫iframe
  2. 母頁傳訊息給iframe頁:母頁(mother.tw)傳訊息給子頁(iframe.tw),讓子頁內容變色。

Demo的頁面在這:

https://letswritetw.github.io/letswrite-postMessage/

Demo頁的原始碼也放在Github上了:

https://github.com/letswritetw/letswrite-postMessage


Summary
postMessage 主頁、iframe頁可互相傳值
Article Name
postMessage 主頁、iframe頁可互相傳值
Description
本篇大綱:前端的一個困擾 管不到 iframe。Google、Facebook也是這樣傳值的。postMessage基本使用、傳值、接值。原始碼、Demo。本篇筆記要記錄的就是A、B頁面iframe的情況下,A傳給B,或B傳給A的問題,該怎麼用postMessage來解決。
Augustus
Let's Write
Let's Write
Publisher Logo

留言