ajaxの最近のブログ記事



もはや当たり前となった javascript とか ajax とか使って


ページ遷移しない web アプリの弱点として、


ブラウザの戻るボタンは罠問題があります。



ブラウザの「戻る」は生理的に染み付いてるものなので、


今さら注意書きで「使っちゃだめよ」とか言っても無駄です。



また、ページ遷移しない場合、パーマリンクどうするよ。って話にもなりますね。



という需要で、ajax の戻る対策をしたライブラリはいろいろあるわけですが、


ちょっと思うことあって自分でも作ってみました。


大いに参考にしたのはこちら。


Ajaxと戻るボタン・ブックマーク



こちらがさらに参考にしてたのはこちら。


location.hashを使ったセッション復元



あと、safari 対応にあたり、SWFAddressも参考にしました。


こっちは flash で同様のことを実現してます。



IE, Firefox については、先のみかログさんの言ってる通りやってます。


で、safari に関しては、history.length が肝っぽい。



SWFAddress のぞいたら、history.length を元に cookie に書き込んだり、


見えない form 作って submit したりうにゃうにゃやってましたが、


hisotry.length をキーとした配列に、location.hash 突っ込んでいったら事足ります。



で、さらに作り直す上で実現したかったのは、以下



  • callback の登録をもちょっとやりやすく

  • safari 対応

  • &以降を get 変数 like に扱う

  • クロスブラウザ対策に Factory メソッドパターンを使う


javascript で factory メソッドを使わない理由


このエントリで書いた、クロスブラウザ対策に Factory メソッドパターンを使う有用な例がこれかなーって思いました。


history 周りの挙動はブラウザによって全く異なるので、


ここはハードコーディングでよいのです。多分。



動作サンプル



万が一使ってみた方おられましたら、フィードバック的なものをいただけると超うれしいです。


あ、YUI依存あります。


extend くらいにしか使ってないので、自分好みのフレームワークに入れ替えたらよいと思います。




で、javascript ちゃんとやりだして、


最初に躓いたっていうか、イマイチ腑に落ちなかったのが


いつの間にか this がどこかいってしまう問題。


多分、初歩的な問題なんだろうけど。



XMLHTTPRequest で callback 指定する時とか、


setTimeout とかの時に、クラスのメソッドを参照渡しすると、


そのクラスの属性が参照できなくなってしまう件である。



function hoge() {
    this.test = 'hello';
}
hoge.prototype = {
    fuga: function() {
      alert(this.test);
    }
}
var hoge_ = new hoge;

//この実行結果は undefined になる。ハズ。
setTimeout(hoge.request, 100);

まあ首をかしげながら、変数をグローバルにしたり、


callback に渡すのはメソッドじゃなくて関数にしたり、


挙句の果てにその関数の中でクラスをもう一度インスタンス化したりして


解決(なかったことに)してたんだけど、



今から思えばまさに迷走である。



こんな感じでやってた。テストしてないので、動くかどうかは知らんです。


動いてもしょうがないし。



var g={}

function hoge() {
g.param='global';
g.text = '';
}

function hoge.prototype = {
request: function() {
var myAjax = new Ajax.Request(
url,
{
method: 'get',
parameters: pars,
onComplete: getResponse
});

},

display: function() {
alert(g.param + g.text);
}
}

function getResponse(o) {
var ins = new hoge();
ins.text = o.responseText;
ins.display();
}

function init() {
var ins = new hoge();
ins.request();
}

Event.observe(window, 'load', init, false);

オブジェクト指向に片思いしてる自分としては、


クラスはそれなりに意味のあるものにしたい。


だから、問い合わせ→データ取得→出力を何とか


一つのクラス内で行いたくって四苦八苦してるのである。


あと、グローバルもなるべく汚したくないしね。



まあ、これで何となく動いてるし、まいっか。


検索してもパキッと出てこないし。


みんなどうしてんだろうとも思うんたけど、


近くの人に聞いてみても、


「this がどっかいっちゃうんですよね~」


「うにゃむにゃむにゃ」って答えだったので、(十中八苦、聞き方が悪い)


放置してた。



これが最近になってなんとなく解決した。


参照を渡せるのは、 php でいうところの static なメソッドのみなんだ。きっと。



だから、 XMLHTTPRequest で callback 指定する時とか、


setTimeout とかの時に this がなくなっちゃうのだ。



これを解決するには、インスタンスをグローバル変数にしてしまえばよい。ハズ。


で、参照渡しされるメソッド内でのみ、そのグローバル変数のインスタンスを使用すればよい。ハズ。



相変わらず、テストはしてないす。



var g={}
function hoge() {
this.param='global';
this.text = '';
}

function hoge.prototype = {
request: function() {
var myAjax = new Ajax.Request(
url,
{
method: 'get',
parameters: pars,
onComplete: g.hoge.getResponse
});

},

display: function() {
alert(this.param + this.text);
},

getResponse: function(o) {
g.hoge.text = o.responseText;
g.hoge.display();
}

}


function init() {
g.hoge = new hoge();
g.hoge.request();
}

Event.observe(window, 'load', init, false);

apply っていう関数使えば何とかなるんじゃないかとも思ったけど、


多分、これ違う。



つーことで体で覚えた javascript の作法でした。


ほんとの正解はどんななんだろう。