一旦サーバーにデータを送って良いなら様々な構成をとることができますが,これをクライアントサイドのみ(サーバーからは静的なファイルの取得のみ)で行う場合どうすればよいでしょうか?
この問題を解決する方法としては主に次の二つの方法が考えられます.
- window.openの引数に渡すurl文字列のクエリ文字列にパラメータを仕込む.
「?」以降にkey=value形式の文字列を挿入する方法です.子ウインドウではこの内容をスクリプトで取得し,画面に表示します. - window.openで子ウインドウを呼び出した後,子ウインドウの持つメソッドを呼び出す.
※その代わり,ドメインの縛りを受けないメリットはあります.
そこで子ウインドウのメソッドを直接呼び出す方法を考えてみましょう.
素朴な実装
最も素朴に考えると次のようなコードとなるでしょう.
呼び出し元(main.htm)のスクリプト
var win = window.open("sub.htm");
win.setValue("sample code");
呼び出し先(sub.htm)のスクリプト
window.onload = function(){
window.setValue = function(text){
document.body.innerHTML = text;
};
};
一見正しいように見えますが,正しく有りません.なぜかというと,window.openを呼び出した後,setValueが存在している保証が無いからです.子ウインドウのonloadイベントによる処理が完了しないと子ウインドウのもつsetValueメソッドは呼び出すことが出来ず,親からはundefinedとして扱われてしまうのです.
一般的なwindowsアプリケーションを触っているとwindow.openによるイベント処理が完了してから次の処理が行われる気がするのですが,htmlアプリケーションではその限りではないのです.
初期化の順番を考慮した実装
では,子ウインドウの初期化処理が完了した後にプログラムが実行されるように出来れば良いわけですから,次のように書き換えたらどうでしょうか?
呼び出し元(main.htm)のスクリプト(その2)
var win = window.open("sub.htm");
win.addEventListener("load", function(){
win.setValue("sample code");
}, false);
子ウインドウでは初期化処理をwindow.onloadプロパティで行なっています.従ってそれよりも後に処理を実行するには,親ウインドウから子ウインドウのaddEventListenerメソッドに実行したい処理を登録すればいいはずです.
しかし実際に試してみると結果はあまり良く有りません.
- chrome・・・正しく動作
- firefox・・・エラー
- opera・・・何も起きない
呼び出し元(main.htm)のスクリプト(その2')
var win = window.open("sub.htm");
setTimeout(function(){
win.addEventListener("load", function(){
win.setValue("sample code");
}, false);
}, 0);
呼び出し先(sub.htm)のスクリプト(その2')
$(function(){
window.setValue = function(text){
document.body.innerHTML = text;
};
});
- jQueryを使ってloadイベントの前に確実に初期化が行われるようにする.
→firefox対策 - loadイベントの登録をsetTimeout関数で囲む
→opera対策
初期化が終わるのを待つ
この問題の根本は親ウインドウから子ウインドウのもつsetValueメソッドが見つからないのが問題なのです.このメソッドは少し待てば何れ使用可能になるはずです.と言う事は,メソッドの呼び出しを子ウインドウの初期化が終わるまで待てればいいはずです.では内容を書き換えてみましょう.
呼び出し元(main.htm)のスクリプト(その3)
var win = window.open("sub.htm");
tryCall();
function tryCall(){
if(!win.setValue){
setTimeout(tryCall, 100);
return;
}
win.setValue("sample code");
}
呼び出し先(sub.htm)のスクリプト(その3)
window.onload = function(){
function setValue(text){
document.body.innerHTML = text;
};
window.setValue = setValue;
};
- 呼び出し元ではsetTimeoutでsetValue関数がセットされることを待っています.
- 呼び出し先では確実に初期化が終了してからsetValue関数を外部に公開するため,一旦ローカル関数で処理を定義し,初期化処理の最後にsetValue関数を公開しています.
この方法であればchrome,firefox,operaでも正しく動作するようです.
※とは言ってもこの他のブラウザで動作するかどうかは確認する必要はありますが・・・
2つめの方法はhttp://defghi1977.html.xdomain.jp/tech/svgMemo/svgMemo.htmで使っています.
3つめの方法はhttp:/defghi1977.html.xdomain.jp/tech/makefonts/makefonts.htmで使っています.
0 件のコメント:
コメントを投稿