履歴 API の操作

HTML5 では、履歴項目を追加および変更するための pushState() および replaceState() メソッドをそれぞれ導入しています。これらのメソッドは popstate イベントと一緒に動作します。

履歴項目の追加と修正

pushState() を使うことで、履歴の状態を変更した後に生成される XMLHttpRequest オブジェクトの HTTP ヘッダー中のリファラも変更されます。リファラは XMLHttpRequest オブジェクトが生成された時点での this となるウィンドウの持つドキュメントの URL となります。

pushState() の例

以下の JavaScript が https://mozilla.org/foo.html で実行されると想定してください。

let stateObj = {
    foo: "bar",
}

history.pushState(stateObj, "page 2", "bar.html")

これにより URL バーには https://mozilla.org/bar.html と表示されますが、ブラウザーは bar.html を読み込むことはなくまたその存在をチェックすることはありません。

ユーザーが https://google.com へ移動し、それから戻るボタンをクリックしたとします。このとき、 URL バーは https://mozilla.org/bar.html を表示し、history.statestateObj になります。popstate イベントはページが再読み込みされたために発行されません。ページそれ自体は bar.html のように見えます。

再び戻るボタンをクリックすると、URL は https://mozilla.org/foo.html へ変化し、 popstate イベントが発行され、状態は null オブジェクトとなります。ここでもまた、popstate イベントを受け取って手動でコンテンツを変更することは可能ですが、戻るという操作によって戻る前のコンテンツが変更されるわけではありません。

pushState() メソッド

pushState() は、 状態オブジェクトtitle (今は無視されます)、(任意で) URL の 3 つの引数を使用します。

これら 3 つの引数について詳細に見ていきましょう。

状態オブジェクト

状態オブジェクトは JavaScript のオブジェクトで、 pushState() によって作成された新しい履歴項目と関連付けられています。ユーザーが新しい状態に遷移するたびに popstate イベントが発行され、そのイベントの state プロパティに履歴項目の状態オブジェクトのコピーが格納されます。 状態オブジェクトはシリアライズ可能なものであれば何でも構いません。Firefox は状態オブジェクトをユーザーのディスクに保存し、ユーザーがブラウザーを再起動した後に復元できるようにするため、状態オブジェクトのシリアライズ表現に 640k 文字というサイズ制限を課しています。もし、シリアライズされた表現がこれより大きい状態オブジェクトを pushState() に渡すと、このメソッドは例外を発生します。これ以上の領域が必要な場合は、 sessionStoragelocalStorage を使用することをおすすめします。

title

Safari 以外のすべてのブラウザーは、現在この引数を無視しています。ただし、将来的には使用する可能性があります。ここで空文字列を渡せば、将来このメソッドが変更されても安全です。あるいは、移動先の状態を表す短いタイトルを渡すこともできます。

URL

新しい履歴項目の URL はこの引数で与えられます。ブラウザーは pushState() の呼び出しの後にはこの URL を読み込もうとしませんが、例えばユーザーがブラウザーを再起動した後などには URL を読み込もうとする可能性があることに注意してください。新しい URL は絶対的である必要はありません。相対的である場合、現在の URL に対して相対的に解決されます。新しい URL は現在の URL と同じオリジンでなければなりません。そうでない場合、pushState() は例外を発生します。この引数はオプションです。指定しなかった場合、文書の現在の URL が設定されます。

メモ: Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) から Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) までの間では、渡されたオブジェクトは JSON を使用してシリアライズされます。 Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3) より、オブジェクトは構造化複製アルゴリズムを使用してシリアライズされます。これにより多種多様なオブジェクトを安全に渡せるようになります。

ある意味では、pushState() の呼び出しは window.location = "#foo" と設定するのと似ています。どちらも、現在の文書に関連する別の履歴項目の生成と有効化を行います。

しかし、 pushState() にはいくらかの利点があります。

  • 新しい URL は、現在の URL と同じオリジンであればどの URL にもなることができます。対照的に、 window.location では同じ document のままで、ハッシュの変更のみが可能です。
  • 必ずしも URL を変更する必要はありません。逆に、 window.location = "#foo"; では、現在のハッシュが #foo でない場合、新しい履歴項目の作成以外のことはできません。
  • 新しい履歴項目に任意のデータを関連付けることができます。ハッシュを基にしたアプローチでは、関連するデータを含めた短い文字列を全てエンコードする必要があります。
  • その後、 title がブラウザーで使用された場合、このデータを(例えばハッシュとは関係なく)使用することができます。

新しい URL が古い URL とハッシュだけ異なっていても、 pushState() は決して hashchange イベントを発行させないことに注意してください。

他の文書では、 null の名前空間 URI を持つ要素を作成します。

replaceState() メソッド

history.replaceState() はちょうど history.pushState() のように動作しますが、 replaceState() は新しく履歴項目を作成するのではなく、現在の履歴項目を修正します。ただし、グローバルなブラウザー履歴に新しい項目が作成されるのを防ぐものではありません。

具体的には、何らかのユーザーのアクションを受け、現在の履歴項目の URL または 状態オブジェクトを更新したい場合に replaceState() が役立ちます。

メモ: Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) から Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) までの間では、渡されたオブジェクトは JSON を使用してシリアライズされます。 Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3) より、オブジェクトは構造化複製アルゴリズムを使用してシリアライズされます。これにより多種多様なオブジェクトを安全に渡せるようになります。

replaceState() の例

https://mozilla.org/foo.html で次の JavaScript を実行したとします。

let stateObj = { foo: "bar" }
history.pushState(stateObj, "page 2", "bar.html")

上記2行の説明は、上記の pushState() メソッドの例 の部分で得ることができます。

次に、https://mozilla.org/bar.html で次の JavaScript を実行したとします。

history.replaceState(stateObj, "page 3", "bar2.html")

これによって URL バーには https://mozilla.org/bar2.html が表示されますが、ブラウザーは bar2.html の読み込みを行わず、bar2.html が存在するかどうかもチェックしません。

仮に今、ユーザーが https://www.microsoft.com へ移動し、戻るボタンを押したとします。この時点で URL バーには https://mozilla.org/bar2.html が表示されています。もしユーザーが再び戻るボタンを押すと、 URL バーには https://mozilla.org/foo.html が表示され、bar.html を完全に回避します。

popstate イベント

アクティブな履歴項目が変更される度にウィンドウへと popstate イベントが発行されます。pushState の呼び出しまたは replaceState の呼び出しの影響によって、アクティベートされた履歴項目が作成された場合、popstate イベントの state プロパティは履歴項目の 状態オブジェクトのコピーを含みます。

使い方の例は popstate を参照してください。

現在の状態を読み取る

ページが読み込まれたとき、 ページには null ではない状態オブジェクトがあるかもしれません。これが起こるのは、例えば、(pushState() または replaceState()) の使用によって)ページに状態オブジェクトが設定されており、ユーザーがブラウザーを再起動した場合です。ページを再読み込みした際にページは onload イベントを受け取りますが popstate イベントは受け取られません。しかしながら history.state プロパティを読み取った場合、popstate が発行された際に取得できるであろう状態オブジェクトを得ることができるでしょう。

このように history.state プロパティを用いることで、 popstate イベントを待つことなく現在の履歴項目の状態を読み取ることができます。

let currentState = history.state

関連情報