jstarted.com
JavaScript/HTML/CSSのノウハウや覚書を掲載するブログ
2014.1.30

pushState、replaceStateでブラウザの履歴を操作する

Category:

ajax系のサイトを作成する際、非同期でページのファイルをロードしたりDOMを操作したりするわけですが、そのままではブラウザバックなどの機能には対応されません。つまり見た目ではページ遷移しているように見えても、バックボタンを押した途端に非同期の内容をすっ飛ばして、普通に遷移してきた前のページに移動してしまう、というなんとも直感的でない動作をします。

これを打開したかったので調べてみたところ、History apiというものに突き当たりました。
Manipulating the browser history - Web developer guide | MDN

history.back()やらは昔から使われている一般的なやつですが、このほかHTML5から履歴の追加・修正を行うメソッドが追加されており、これを使うことで当初の目的が達成できるようでした。最初はhistoryの扱いがとっつきにくくて混乱しましたが、いじっているうちになんとなく操作感がつかめたように思います。概ね以下のような感じ。

  • pushState、replaceStateとも、第一引数に値を入力してhistory.stateの値を変更できる。
  • pushStateで履歴を追加すると、今いる位置から追加した履歴の位置に移動する。(1つ先に進んだかたちになる。)
  • replaceStateで履歴を修正した場合、今いる履歴の位置は変わらない。
  • pushState、replaceStateとも、第三引数に値を入力してURLを変更できる。
  • 履歴を移動した際にjsでなんらかの処理を行いたい場合は、window.onpopstateを使えばよい。
  • window.onpopstate内の条件分岐でhistory.stateを参照するようにすれば、
    ajaxサイトでの履歴移動でも各ページ毎の処理を行えるようになる(はず)。
  • pushStateで履歴を追加・移動しただけではwindow.onpopstateは発火しない。
  • そもそもIE9以下で対応していない。

業務であつかうには最後がもっとも重要のようにも思いますが、いったん無視するとして、これらの操作感を味わえるテスト用のコードを以下に書きました。

var elm = {
	pushState : $('#pushState'),
	replaceState : $('#replaceState'),
	box : $('#box')
};

elm.pushState.on('click', function(event) {
	event.preventDefault();
	history.pushState('test_pushState', null, '#push_state');
});

elm.replaceState.on('click', function(event) {
	event.preventDefault();
	history.replaceState('test_replaceState', null, '#replace_state');
});

window.onpopstate = function(){
	if( history.state == 'test_pushState' || history.state == 'test_replaceState' ){
		elm.box.prepend('<p>' + new Date() + ' window.onpopstateが実行されました。history.stateは' + history.state + 'です。</p>');
	}
};

動作のサンプルはこちら
history.pushStateとreplaceStateのテスト - jsdo.it

jstarted.comはamazon.co.jpを宣伝しリンクすることによってサイトが紹介料を
獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、
Amazonアソシエイト・プログラムの参加者です。

クリエイティブ・コモンズ・ライセンス
jstarted.com by yoichi kobayashi is licensed under a Creative Commons 表示 3.0 非移植 License.