読者です 読者をやめる 読者になる 読者になる

tohokuaikiのチラシの裏

技術的ネタとか。

Confluenceのプラグイン開発を承ります。ご連絡はこちらのホームページからお願いいたします。

postMessageを簡単に

JavaScript

frame間でJavaScript操作するのにpostMessageするのだけど、なんで今回使ったかというとローカルに置いた静的HTMLで使いたかったので。この場合、オリジンが無いのでChromeとかSafariはセキュリティエラーで引っかかってしまう。

下準備

使うのは、jQueryでpostMessageをやり取りするBen AlmanさんのjQuery postMessage
あと、jQuery.param()でシリアライズしたのを元に戻すのに、これを使った

汎用のメッセージレシーバを作る

とりあえず、こんな感じ
messageReceiver.js

var setMessageReceiver;
(function($){
    setMessageReceiver = function(callbacks)
    {
        var data,param,retval ;
        var target_url = arguments[1] || "*";
        $.receiveMessage(function(e) {
            data = $.deserialize(e.data);
            if (data.method){
                param = data.param || {};
                if (typeof(callbacks[data.method]) == "function"){
                    retval = callbacks[data.method].call(this, param);
                    if (data.retval){
                        $.postMessage({
                          method: data.method+'Return',
                          param: retval
                        }, target_url, e.source);
                    }
                }
            }
        });
    }
})(jQuery);

フレームにレシーバーを設置

さっきのsetMessageReceiver関数を使って、callbackする関数を決めて設置。
例えば、こんな感じ。

    <script>
    setMessageReceiver({
      getRootpath: function(param){
          return param.a + param.b;
      }
    });
    </script>

postMessageする

さっきのレシーバーを仕掛けたフレームに対して、こんな感じで。

      jQuery.postMessage({method: 'getRootpath', param:{a: 1, b:2}, retval:true}, '*', parent);

第一引数は、レシーバーのcallback関数の指定。param要素でパラメータと、retvalをtrueにすることで再度向こうからこっちにpostMessageしてくれる。

postMessageで返り値がある場合

ということは、postMessageしたフレーム側にもレシーバーを作らないといけない。その場合、postMessageしたmethod名に"Return"を付けたものでcallbackされる。

つまり、先ほどのpostMessageの例だと、

setMessageReceiver({
  getRootpathReturn: function(retval){
      /* ここにretvalを使った処理 */
  }
});

となる。

この場合、callbackとなるのでグローバル変数を使ってproxyするかEventListenするしかないのだけど、EventListenがよくわからず。https://developer.mozilla.org/ja/docs/DOM/window.postMessage とかみると、

jQuery(window).bind('message', callback);

とかでいけそうなんだけどなー。