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

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 的網址,避免外部可能的攻擊。