History API を取り扱う
HTML5 では pushState()
および replaceState()
メソッドが導入され、それぞれにより履歴エントリの追加と修正が可能となりました。 これらのメソッドは window.onpopstate
イベントと連動して動作します。
履歴エントリの追加と修正
pushState()
を使うことで、履歴の状態を変更した後に生成される XMLHttpRequest
オブジェクトの HTTP ヘッダー中のリファラも変更されます。リファラは XMLHttpRequest
オブジェクトが生成された時点での this
となるウィンドウの持つドキュメントの URL となります。
pushState() の例
以下の JavaScript は http://mozilla.org/foo.html において実行されると仮定します:
let stateObj = {
foo: "bar",
};
history.pushState(stateObj, "page 2", "bar.html");
これにより URL バーには http://mozilla.org/bar.html と表示されますが、ブラウザは bar.html
をロードすることはなくまたその存在をチェックすることはありません。
ユーザが http://google.com に移動し、それから戻るボタンをクリックしたとします。このとき、URL バーは http://mozilla.org/bar.html を表示し、history.state
は stateObj
になります。popstate イベントはページがリロードされたために発火しません。ページそれ自体は bar.html のように見えます。
再び戻るボタンをクリックすると、URL は http://mozilla.org/foo.html へ変化し、 popstate
イベントが発火され、state は null オブジェクトとなります。ここでもまた、popstate
イベントを受け取って手動でコンテンツを変更することは可能ですが、戻るという操作によって戻る前のコンテンツが変更されるわけではありません。
Note: Although history.back()
normally behaves the same way as clicking the Back button, the history.back()
method acts differently from the browser Back button after using history.pushState()
. Calling history.back()
after history.pushState()
does not raise a popstate
event while clicking on the browser's Back button does raise the event.
pushState() メソッド
pushState()
は、state オブジェクト、タイトル(現在のところ無視されます)、そしてURL(任意)の3つのパラメータを使用します。これら3つのパラメータについて詳細に見ていきましょう:
-
state オブジェクト — state オブジェクトは
pushState()
によって作成される新しい履歴エントリに関連付けられる JavaScript オブジェクトです。ユーザーが新しいエントリに移動すればいつでも、popstate
イベントが発火して、履歴エントリの state オブジェクトのコピーがイベントのstate
プロパティへと含まれることとなります。state オブジェクトは何であってもシリアライズされます。Firefox はユーザーのディスクに state オブジェクトを保存し、ユーザーがブラウザを再起動した際に state オブジェクトを復元するため、シリアライズされた状態での state オブジェクトの最大文字数は640000文字と、サイズの制限がされています。シリアライズ後にこの最大文字数を上回ることになる state オブジェクトを
pushState()
に渡した場合、pushState()
は例外を投げます。これを上回るスペースが必要な場合、sessionStorage
またはlocalStorage
の使用を推奨します。 -
タイトル — Safari 以外のブラウザはこのパラメータを無視します。しかし将来的には使えるようになるかもしれません。将来的な変更に備えて、空の文字列を渡しておくべきでしょう。あるいは、移動しようとしている先の状態を示す短いタイトルを渡しておくこともできます。
-
URL — このパラメーターは、新しい履歴エントリの URL が指定します。
pushState()
の呼び出しの後、ブラウザはこの URL のロードを行わないと注記しておきますが、ユーザーがブラウザを再起動させた後などでは、新しく指定された URL をロードすることがあります。新しい URL は絶対パスである必要は無く、相対パスであった場合は、現在のURLとの相対関係が解決されます。新しい URL は現在の URLと same origin でなければなりません。でなければpushState()
は例外を発生させるでしょう。このパラメータは任意であり、指定されなかった場合は現在のドキュメントの URL が設定されます。
ある意味では、pushState()
の呼び出しは window.location = "#foo";
と設定するのと似ています。どちらも、現在のドキュメントに関連する別の履歴エントリの生成とアクティベートを行います。ですが pushState()
にはいくらかの利点があります:
- 新しい URL は、現在の URL と同じドメインであればどの URL にもなることができます。対照的に、
window.location
では hash の変更しかできず、同じdocument
のままとなります。 - 必ずしも URL を変更する必要はありません。対照的に、
window.location = "#foo";
では、現在の hash が#foo
でない場合、新しい履歴エントリの作成以外のことはできません。 - 新しい履歴エントリに任意のデータを関連付けることができます。hash を基にしたアプローチでは、関連するデータを含めた短い文字列を全てエンコードする必要があります。
- If
title
is subsequently used by browsers, this data can be utilized (independent of, say, the hash).
新しい URLが、変更前のURLから hash のみを変更した URL である場合であっても、 pushState()
は hashchange
イベントを発火させることはないと注記しておきます。
In a XUL document, it creates the specified XUL element.
In other documents, it creates an element with a null
namespace URI.
replaceState() メソッド
history.replaceState()
は丁度 history.pushState()
のように動作しますが、pushState()
と異なる点として、 replaceState()
は新しく履歴エントリを作成する代わりに現在の履歴エントリを修正します。Note that this doesn't prevent the creation of a new entry in the global browser history.
具体的には、何らかのユーザーのアクションを受け、現在の履歴エントリの URL または state オブジェクトを更新したい場合に replaceState()
が役立ちます。
replaceState() の例
仮に http://mozilla.org/foo.html
は次の JavaScript を実行するものとします。
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
この2行のコードの説明は pushState()の例 のセクションで見ることができます。次に、http://mozilla.org/bar.html
が次の JavaScript を実行するものとします。
history.replaceState(stateObj, "page 3", "bar2.html");
これによってアドレスバーには http://mozilla.org/bar2.html
が表示されますが、ブラウザは bar2.html
の読み込みを行わず、bar2.html が存在するかどうかもチェックしません。
仮に今、ユーザーが http://www.microsoft.com
に移動し、戻るボタンを押したとします。この時点でアドレスバーには http://mozilla.org/bar2.html
が表示されています。もしユーザーが再び戻るボタンを押すと、アドレスバーには http://mozilla.org/foo.html
が表示され、bar.html
を完全に回避します。
popstate イベント
アクティブな履歴エントリが変更される度にウィンドウへと popstate
イベントが発行されます。pushState
の呼び出しまたは replaceState
の呼び出しの影響によって、アクティベートされた履歴エントリが作成された場合、popstate
イベントの state
プロパティは履歴エントリの state オブジェクトのコピーを含みます。
使い方のサンプルは window.onpopstate
を参照してください。
現在の状態を読み取る
ページが読み込まれたとき、 ページは null ではない state オブジェクトを持っているかもしれません。これは例えば、(pushState()
または replaceState()
) の使用によって)ページに state オブジェクトが設定されており、ユーザーがブラウザを再起動した場合に起こりえます。ページを再読み込みした際にページは onload
イベントを受け取りますが popstate
イベントは受け取られません。しかしながら history.state
プロパティを読み取った場合、popstate
が発火した際に取得できるであろう state オブジェクトを得ることができるでしょう。
このように history.state
プロパティを用いることで、 popstate
イベントを待つことなく現在の履歴エントリの state を読み取ることができます:
let currentState = history.state;