最近在公司專案學到了滿好用的功能 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 的網址,避免外部可能的攻擊。