window.postMessageを使ってみる

window.postMessageについて、MDNでの「説明では Window オブジェクト間で安全にクロスドメイン通信を可能にするためのメソッドです。」 とのこと。

windowオブジェクト間って何だ

実際のコードでwindowオブジェクト間という状況がどういうものかを表現してみる。

端的に言うと、winow.openで開いた状況がそれにあたると思います。
というわけで、二つのファイルを用意します。
以下実験用に二つのhtmlファイルを用意する。

index.htmlのソースは以下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <button onclick="raisePopUp()">raisePopUp</button>
</head>
<body>    
</body>
<script>
    let hellow = 'hello world'
    console.log(hellow)
    function raisePopUp() {
        // 以下の例だと新しいタブでページが開かれる
        //window.open("./popup.html","test")
        
        // こちらの例だと新しいwindowが開かれる。
        window.open("./popup.html","test",'width=500,height=500')
    }
</script>
</html>

popup.htmlのソースは以下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PopUp</title>
</head>
<body>
    <h1>PopupWindowだよ</h1>    
</body>
<script>
</script>
</html>

index.htmlをChromeで開くとraisePopUpというボタンがあるので、これをクリックする。

すると、新しいwindowでpopup.html が開かれる。

windowオブジェクト(index.html)のボタンからwindowオブジェクト(popup.html)が開かれた。
ソースも含めると少し長くなったけど、上記したものがwindow間という状況となります。

では、この二つのwindow間でやり取りする場合、どういう方法があるのか。
ざっと思いつくのがサーバサイドの経由する方法。(お作法的にどうなのってのもあるけど、思いついたやつだからね)
・httpリクエストのgetでクエリストリングを使ってメッセージを送る
・httpリクエストのpostのbody内にメッセージを埋め込む
・サーバサイドのセッションを使ったり
クライアントサイドだと
・hiddenの要素に値を入れておいて、window.documentから読み取ったり
Window.localStorage使ったり
・window.postMessageを使ったり

ほかにもやりようはあるんだろうけど、今回はwindow.postMessageです。

window.postMessageの例

先ほどの二つのファイルをベースに実験用コードを編集していきます。
変更点はハイライトしています。

index.html
変更点としては、
①windowオブジェクトを変数に格納したこと。
②postMessageするためのボタンを配置とメソッドの定義

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <button onclick="raisePopUp()">raisePopUp</button>
    <button onclick="postingMessage()">PostMessage</button>
</head>
<body>    
</body>
<script>
    let hellow = 'hello world';
    let popupWindow = null;
    console.log(hellow);
    function raisePopUp() {
        // 以下の例だと新しいタブでページが開かれる
        //window.open("./popup.html","test");
        
        // こちらの例だと新しいwindowが開かれる。
        popupWindow = window.open("./popup.html","test",'width=500,height=500');
    }
    function postingMessage(){
        debugger
        if(!popupWindow) return;
        popupWindow.postMessage("hello!", "*");

    }
</script>
</html>

次にメッセージを受け取る側のソースコード

popup.html
こちらの変更点は
①受け取ったメッセージを表示する要素を配置<h2>
②window.addEventListenerでメッセージを受け取った際に発火させるイベントリスナーを登録
③受け取ったメッセージを表示させるメソッドを定義

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PopUp</title>
</head>

<body>
    <h1>PopupWindowだよ</h1>
    <h2 id="receivedMessage"></h2>
</body>
<script>
    window.addEventListener("message", receiveMessage, false);

    function receiveMessage(event) {
        debugger
        document.getElementById("receivedMessage").innerText = event.data
    }
</script>

</html>

これらを二つ実際に動かしてみると、debuggerでちゃんととまる。
実際にどんなデータを受け取れるのか、などを見てみると勉強になる。

あくまで上記は例なので、送信者の識別情報を確かめたりしていない。
やり方はこちらに詳しく書いてある。