Ajaxと組み合わせて便利なHistory APIを使おう
こんにちは。PR TIMESフロント・エンジニアの山田です。
弊社ではAjaxを使ったサイトやサービスも多く運営しています。
さて、そのAjaxですがページ遷移なしにコンテンツを切り替える場合、当然ながらそのままではブラウザのURLも変わりません。これではユーザーが直接読み込み先にアクセスしたり、ブラウザのBACKボタンで前に戻ったりできないので不便です。そんな時に使えるのが、Hisotry API。これはブラウザの履歴をJavascriptから管理、操作できる便利なAPIです。
まず以下の4つは以前からあり、古いブラウザでも動作します。
history.back();//表示した履歴の1つ前のページにもどる history.go(4);//表示した履歴の4つ前のページにもどる history.go(2);//表示した履歴の2つ先のページに進む history.forward();//表示した履歴の1つ先のページヘ進む
さてHTML5ではこれらに加えてpushState,replaceStateという関数が加わりました。
history.pushState(state, title, url); history.replaceState(state, title, url);
state…stateオブジェクト。history.stateでこの値にアクセスできます。
title…現状使用できません。将来に備えた引数です。空白にできないのでnullを指定してください。
url…履歴に追加するURL。ただしセキュリティ上、外部サイトを指定することはできません。
pushStateはブラウザに任意の履歴を追加しアドレスバーのURLを書き換えます。replaceStateは現在の履歴を書き換えることができます。履歴の操作とアドレスバーのURLを書き換えるだけで、実際にリンクはしません。
さらにpopstateを使うことによって、URLが変わったときにイベントを発動することができます。
window.addEventListener("popstate", function);
Ajaxと組み合わせた実際のサンプルコードです。
“読み込む”ボタンを押すとAjaxでtest.htmlを読み込み、div内に表示します。このときURLをhttp://~~~/test.htmlに書き換え、履歴に追加。またpopstateを使うことで、ブラウザの戻る/進むボタンでコンテンツ切り替えができます。
<a href="test.html" onclick="loadTestFile(event);">読み込む</a> <div id="contents"></div>
var loaded; function loadTestFile(event){ event.preventDefault(); $.ajax({ type: "GET", url: "test.html", dataType: "html", success: function(out) { loaded = out; $("#contents").html(out); history.pushState("testState", null, "/test.html"); } }); } window.addEventListener("popstate", function(event){ if(event.state == null){ $("#contents").html(""); }else if(event.state == "testState"){ $("#contents").html(loaded); } });
History APIのブラウザ対応状況はこちらをご覧ください。http://caniuse.com/#feat=history
旧IEなどは動作しないので、対象に含める場合は代替の手段が必要になります。
例えばIE9の場合、上記の例ではAjaxでtest.htmlが読み込まれますがURLは変わりません。
これではブックマークやシェアしてもらう時に不便です。
その場合、以下のようにハッシュをつけるなどして管理すると良いです。
if ("pushState" in history){ history.pushState("testState", null, "/test.html"); }else{ location.hash = "test"; }
History APIと直接は関係ありませんが、URLを書き換える時にタイトルなどもコンテンツに合わせて書き換えた方が親切です。
以下のような方法で読み込み先HTMLのタイトルを取得して、書き換えることができます。
$.ajax({ type: "GET", url: "test.html", dataType: "html", success: function(out) { loaded = out; $("#contents").html(out); var titleScr = /<title>(.*)<\/title>/; var titleStr = titleScr.exec(out)[1]; $("title").text(titleStr); history.pushState("testState", null, "/test.html"); } });