2007-09-27
jQuery の $(document).ready(fn) と IE
IE 6 と jQuery 1.1.4 ですが,$(document).ready(fn) イベントが,ページを表示するたびに実行されるような気がします。
単純に,
$(document).ready(function () {
alert('hoge');
});
みたいなコードを読み込む html 1 があったとして,そこからリンク等で html 2 に遷移させます。
で,html 2 からブラウザの「戻る」ボタン等で html 1 に戻ると,再度 alert が表示されます。
Firefox / Opera / Safari では,html 1 に戻っても ready イベントは再度実行はされません(すでに ready イベントが発生した後の DOM ツリーになっていますので問題はありません)。
jQuery 自体を JavaScript で遅延ロードさせているからかなぁ。もうちょっと検証してみます。
追記
遅延ロードは関係なかったです。
以降 Cache-Control については無視します。
検証用コード。
<html> <head> <title>HTML 1</title> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $(function () { alert('ready'); if ($('#hidden1').val() != 'loaded') { $('#hidden1').val('loaded'); $('#btn1').click( function () { alert('clicked'); } ); alert('loaded for the first time'); } }); </script> </head> <body> <h1>HTML 1</h1> <p> <a href="html2.html">to HTML 2</a> </p> <p> <input type="button" id="btn1" value="押す" /> <input type="hidden" name="dummy" id="hidden1" value="" /> </p> </body> </html>
html2.html は適宜用意するとして。
- HTML 1 を開く
- 「ready」と alert が出る
- 「loaded for the first time」と alert が出る
- 「押す」ボタンを押すと「clicked」と alert が出る
- HTML 2 へのリンクをクリックする
- 「戻る」ボタンで戻る
- 「押す」ボタンを押すと「clicked」と alert が出る
IE 6 の場合,
- HTML 1 を開く
- 「ready」と alert が出る
- 「loaded for the first time」と alert が出る
- 「押す」ボタンを押すと「clicked」と alert が出る
- HTML 2 へのリンクをクリックする
- 「戻る」ボタンで戻る
- 「ready」と alert が出る
- 「押す」ボタンを押しても「clicked」と alert が出ない
どういうことかというと,IE 以外のモダンブラウザの場合,ブラウザの「戻る」等で遷移した場合,JavaScript でいじられた DOM ツリー・イベントリスナ系はそのままに戻ります。ready イベントは発生しません。
IE の場合,ブラウザの「戻る」等で遷移した場合,サーバから html をロードした時点まで巻戻り(DOM ツリー・イベントリスナも初期状態になります),再度 JavaScript を実行します。
で IE のときは裏技的に?<input>タグの値を設定しておくことで挙動を変えることができますが*1,そのかわりイベントリスナ等もリセットされているのでボタンを押してもメッセージが出ません。また DOM ツリーもリセットされるので,DOM ツリーをいじって既ロードかどうかを判定させることはできません。
JavaScript 詳しくないんで間違いとか多々あるかもしれません。
jQuery の $.getJSON() と IE ではまった
今つくっているサイトでは,html のエンコーディングを Shift_JIS にしてるんで,合わせるために JavaScript のエンコーディングも Shift_JIS にしてます(jQuery だけは念のため UTF-8 指定してますけど)。
で,そこで JSON データをやりとりしているんですが,全部 Shift_JIS に統一していたんで,
- Content-Type: text/javascript; charset=Shift_JIS
な JSON を吐くようにしていたんですが,どうも IE 6 で挙動が安定しない。
初回の Ajax ネゴのときにはうまくいっても,そこからブラウザで「進む」「戻る」してもう一度 Ajax ネゴると文字化けしたり,初回の Ajax ネゴから文字化けどころかまったくやりとりできなかったり。
うーむ,と思ってネットをいろいろあさっていたら,
な記事を発見したんですが,元サイトがリニューアル中で何が書いてあったか不明。気になる〜。
じゃあってことで元ネタを探してみたらちょっと古い記事ですが,
というのを発見。JSON の Content-Type を text/html で返すと危ないよ,とのことですけど,頭がわるいので,この記事の前半と後半(exploit)のつながりがいまいちわからない。
ともあれ,text/javascript というのは obsolete ですか。でも RFC がどうこういっても実際の実装はブラウザによりけりですよね。と思いもちょっとたぐってみると,これもちょっと昔の記事ですが
このサイトを合わせて見ると,Opera 8.5 だと text/x-javascript がベターぽくて,(当時の)Safari のことを考えると charset 指定はしたほうがいいっぽい。
ということで,x-javascript にしようかとも思ったんですが,結局,文字化けがらみだし〜ということで
にしてみました。実質文字コードを変えただけです。
一応 IE で安定したっぽいし,Opera 9.23 だとこれでも OK でした。Safari 2.x でも OK。
結論。コンテンツを Shift_JIS に統一していても少なくとも JSON データの charset は UTF-8 のほうが無難?
ちなみに jQuery を読解してみたら,json のパースは eval を使っているぽい。JSONP でなければまぁ eval でも構わないというかサーバアプリサイドの責務にしちゃってもいいかなと私も思います。
おまけ:やはり jQuery と IE ではまったところ
<select id="hoge"> <option>hahaha</option> <option>fufufu</option> </select>
みたいな html で,
$('#hoge').val('fufufu');
とすると,Firefox / Opera / Safari だとうまく選択されるのに,IE だとブランクになってしまいます。
面倒でも
<select id="hoge"> <option value="hahaha">hahaha</option> <option value="fufufu">fufufu</option> </select>
みたく value を指定しておかないとだめでした。
*1:type = hidden じゃなくて text にするとわかりやすいかも
