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に感謝!