Ajax通信は便利だが、厄介な問題を抱えている。
ブラウザの「戻る」ボタンが使えないのだ。
Historyが残らないのである。
これはかなりマズイ。
例えば割と時間をかけて取得した画面を表示した後、一旦別の画面に遷移したが、また直前の(時間をかけて取得した)画面へ戻りたい時、ブラウザの「戻る」で直前の履歴に戻れなければ、もう一度時間をかけて画面の情報を取得しなければならない。
これではユーザから必ずクレームが来る。
ところがjavascriptにこれを解決する手段が無いのだ。
(ハック的な実現方法はあるらしいが、使わないほうが無難だ。)
途方に暮れていると、html5でまさにこれを解決する手段が提供されていた。
history.pushStateである。
早速使ってみよう。
その前にこの関数のcallingシーケンスは以下だ。
history.pushState(stateObj, title, url); stateObj: 履歴エントリに関連付けられるJavaScriptオブジェクト title: 将来的拡張(現在未使用です。) url: 履歴エントリのURL
以下はサンプルだ。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script src="./jquery-1.7.2.min.js"></script> <title>javascript test</title> <script type="text/javascript"> var doajax = function(id, url) { document.body.style.cursor = 'wait'; $.ajax({ type: "get", url: url, dataType: "text", success: function(res){ $(id).html(res); if(window.history && window.history.pushState) { history.pushState({response: res, id: id}, null); } }, complete: function(xhr, textStatus) { document.body.style.cursor = 'auto'; }, error: function(xhr, textStatus, error) { console.log('error...: ' + textStatus + ' :' + error); } }); } window.addEventListener( "popstate", function(event) { if(event.state != null) { $(event.state.id).html(event.state.response); } else { $("#target").html("hello, history"); } } ); </script> </head> <body> <div id="target">hello, history</div> <input type="button" value="go 1!" onClick="doajax('#target', 'http://localhost/1.txt')"><br /> <input type="button" value="go 2!" onClick="doajax('#target', 'http://localhost/2.txt')"><br /> <input type="button" value="go 3!" onClick="doajax('#target', 'http://localhost/3.txt')"><br /> </body> </html>
DIV要素に表示された「hello, history」を「go 1!」、「go 2!」、「go 3!」ボタンで書き換える。
書き換えはajaxで行う。
取得するデータは単なるtextファイルだ。
local環境に1.txt、2.txt、3.txtを用意する。
ajaxのコールバックsuccessでpushStateを使う。
if(window.history && window.history.pushState) { history.pushState({response: res, id: id}, null); }
最初のif文はpushStateの実装のチェックだ。
history.pushStateの第一引数にsuccessのレスポンス(1.txt or 2.txt or 3.txtの内容)と更新する要素のidを持つオブジェクトを指定する。第3引数は省略している。
(省略するとブラウザのURLは変わらない。指定すればこの内容がURLに表示される。)
このオブジェクトはaddEventListenerで登録する”popstate”コールバックで送られてくる。
“popstate”コールバックはブラウザの「戻る」「進む」ボタン押下時に呼び出される。
このタイミングでajaxのsuccessと同様の処理を行う。
window.addEventListener( "popstate", function(event) { if(event.state != null) { $(event.state.id).html(event.state.response); } else { $("#target").html("hello, history"); } } );
event.stateがnullでなければ履歴が存在するので、event.stateの内容(successのレスポンスと更新対象の要素ID)でDOMを更新する。event.stateがnullであれば履歴が無いので初期状態に戻す。
これで履歴が再現できる。
html5に感謝!