最近在公司專案學到了滿好用的功能 postMessage,當今天使用到跨視窗iframe或是openWindow,原本parent頁面需要傳遞訊息給內頁iframe或是tab頁,就可以利用postMessage來傳遞資料。接下來會建立demo頁面,介紹一下iframe跟window open的使用方法。

JavaScript

window.postMessage() 方法被調用時,會在所有頁面腳本執行完畢之後
e.g., 在該方法之後設置的事件、之前設置的timeout 事件,etc.)
向目標窗口派發一個 MessageEvent 消息。

MessageEvent消息有四個屬性需要注意:
message 屬性表示該message 的類型;
data 屬性為 window.postMessage 的第一個參數;
origin 屬性表示調用 window.postMessage() 方法時調用頁面的當前狀態;
source 屬性記錄調用 window.postMessage() 方法的窗口信息。

window postMessage 介紹

postMessage的調用方式 => targetWindow.postMessage(message, targetOrigin, [transfer]),targetWindow會是某個窗口,targetOrigin則是指定可傳遞的端口網域,transfer是一串和message 同時傳遞的 Transferable 對象。

targetWindow 可設定目標 :

  • Window.open
  • Window.opener
  • HTMLIFrameElement.contentWindow (embedded iframe ),
  • Window.parent ( parent window embedded iframe)
  • Window.frames + an index value (named or numeric).

window postMessage MDN

window open demo page

首先要建立送出訊息跟接受訊息的頁面,送出訊息頁面主要做兩件事情,開啟視窗並指定為變數、向剛剛開啟視窗頁面送出訊息。javascript沒有特別難度,所以就直接看我建立好的頁面,底下是處理的html還有javascript。

範例 :

  • 使用步驟 先點選開啟視窗
  • 輸入隨意字串
  • 點選送出按鈕

ps.分頁切換需要用瀏覽器app safari、chrome

Source : Open Window Demo Page

send.html

<!DOCTYPE html>
...
<h1 class="cover-heading">HTML send Post Message demo sample.</h1>
<p class="lead">
<button id="openWindow" type="button" class="btn btn-info">開啟視窗</button>
</p>
<div class="input-group">
<input type="text" id="messageText" class="form-control" placeholder="輸入訊息">
<div class="input-group-append">
<button id="postWindow" class="btn btn-info btn-outline-secondary" type="button">送出訊息</button>
</div>
</div>
...
<script>
// 建立變數
var createWindow;
document.getElementById('openWindow').addEventListener('click',function(e){
// 將變數 assign window open 物件
createWindow = window.open("./receive.html");
});
document.getElementById('postWindow').addEventListener('click',function(e){
sendMsg();
});
function sendMsg() {
var message = document.getElementById("messageText").value;
var domain = window.location.origin;
// post message
createWindow.postMessage(message, domain);
// focus windowOpen
createWindow.focus();
document.getElementById("messageText").value = '';
}
</script>
...
</html>

recevie.html

<!DOCTYPE html>
...
<p class="lead">
<h2 id="response"></h2>
</p>
...
<script>
window.addEventListener("message", getMessage, false);
function getMessage(e) {
var content = '';
// e.data 接受傳遞訊息
content += "Get Message =>" + e.data + '<br>';
// e.origin 接受訊息domain
content += "Url from " + e.origin;
document.getElementById("response").innerHTML = "<p>" + content + "</p>";
};
</script>
...
</html>

iframe demo page

這個會比較特別,window open是原本頁面傳給開啟頁面,iframe則會使用iframe embed內部的網站傳遞資料給外部parent,範例情境大概是修正iframe的高度,

範例 : (白色區塊是使用iframe)

  • 點選iframe 內 伸縮高度按鈕
  • 點擊按鈕後,會變化body高度,並傳值到parent window
  • parent window接受到值後,變化iframe style height

Source : Iframe Demo Page

iframe.html

...
<script>
// 接受傳遞訊息 變化iframe height
window.addEventListener("message", getMessage, false);
function getMessage(e) {
if(e.data.event_id) {
document.getElementById('addIframe').style.height = e.data.data + 'px';
}
};
</script>
...

embed.html

...
<script>
document.getElementById('postWindow').addEventListener('click', function (e) {
sendMsg();
});
function sendMsg() {
var height = document.body.scrollHeight;
// 向parent window 送出訊息
window.parent.postMessage(
{
event_id: 'my_cors_message',
data: height
},
"*" // or "www.parentpage.com"
);
}
</script>
...

以上就是簡單的demo,還有更多延伸的運用,例如做出開視窗會員註冊,送出後傳遞資料回原本頁面渲染畫面。另外當你今天不得不用iframe的話,postMessage會非常好用,賦予iframe更有彈性。另外提醒一下,實際運用要記得判斷post Message的網址,避免外部可能的攻擊。