Window: popstate イベント

popstateWindow インターフェイスのイベントで、ユーザーがセッション履歴を操作している間にアクティブな履歴項目が変更されたときに発行されます。これは現在の履歴項目をユーザーが最後に訪れたページのものに変更するか、または history.pushState() が履歴項目を履歴スタックに追加するために使用されていた場合、その履歴項目が代わりに使用されます。

構文

このイベント名を addEventListener() などのメソッドで使用するか、イベントハンドラープロパティを設定するかしてください。

js
addEventListener("popstate", (event) => {});
onpopstate = (event) => {};

イベント型

PopStateEvent です。 Event を継承しています。

Event PopStateEvent

イベントプロパティ

PopStateEvent.state 読取専用

pushState() または replaceState() に提供された情報のコピーを返します。

イベントハンドラーの別名

Window インターフェイスに加えて、イベントハンドラープロパティ onpopstate は以下の要素でも利用できます。

履歴スタック

アクティブ化される履歴項目が history.pushState() の呼び出しによって作成されたものである場合、または history.replaceState() の呼び出しの影響を受けた場合、 popstate イベントの state プロパティには履歴項目の状態オブジェクトのコピーが格納されます。

これらのメソッドと対応するイベントは、履歴スタックにデータを追加するために使用することができ、動的に生成されたページを再構築したり、同じ Document に留まりながら表示するコンテンツの状態を変更したりするために使用することができます。

ただ、 history.pushState()history.replaceState() を呼び出すだけでは、 popstate イベントが発行されないことに注意してください。 popstate イベントは、戻るボタンや進むボタンをクリックする(あるいは JavaScript で history.back()history.forward() を呼び出す)など、ブラウザーの操作によって発行されます。

ブラウザーは、ページ読み込み時に popstate イベントを異なる方法で処理する傾向があります。 Chrome (v34 以前)と Safari ではページ読み込み時に常に popstate イベントが発行されますが、 Firefox では発行されません。

メモ: popstate イベントを処理する関数を書くときには、 window.location のようなプロパティはすでに状態の変化を反映していますが(それが現在の URL に影響する場合)、 document はまだ反映されていないかもしれないことを考慮に入れておくことが重要です。新しい文書の状態が完全に反映された瞬間を捉えることが目的であれば、遅延ゼロの setTimeout() メソッド呼び出しを使用して、処理を行う内部の callback 関数をブラウザーのイベントループの最後に効果的に配置する必要があります。例えば window.onpopstate = () => setTimeout(doSomeThing, 0); のようにします。

popstate が送信される場面

ブラウザーは迷惑なポップアップに対抗するために、ページが操作されない限り popstate イベントをすべて発行しないことがあります。

この節では、ブラウザーが潜在的に popstate イベントを発行する場合(つまり、ページが操作された場合)に従う手順を記述します。

ユーザーがブラウザーの 戻る ボタンを押すなどして遷移が発生した場合、 popstate イベントは新しい場所に遷移するためのプロセスの終了間際に発行されます。新しい場所の読み込み(必要な場合)、表示、可視化などが行われた後に pageshow イベントが送信され、持続的なユーザー状態情報が復元されて hashchange イベントが送信される前に発行されます。

popstate イベントが発行されるタイミングをよりよく理解するために、ユーザーがサイトを移動するか、履歴をプログラムで走査することによって、現在の履歴項目が変更されたときに発行されるイベントのシーケンスを単純化して考えてみましょう。ここでは、現在の履歴項目を新しい項目と呼ぶものに変更する遷移を示します。現在のページのセッション履歴スタック項目は現在の項目と呼びます。

  1. もし新しい項目 が現在、既存の Document を含んでいなければ、続行する前にコンテンツを取得し、その Document を作成します。これは DOMContentLoadedload イベントを最終的に文書を含む Window に送信しますが、以下のステップはその間に実行され続けます。
  2. 現在の項目のタイトルが履歴 API のメソッド、 (pushState() または replaceState()) の何れかで設定されなかった場合は、その項目のタイトルが document.title 属性が返す文字列に設定されます。
  3. もし、ブラウザーが現在の項目から離れる前に保存したい状態情報を持っている場合は、保存します。このとき、その項目は「ユーザーの状態を保持した」とみなされます。ブラウザーが履歴セッションの項目に追加する可能性のあるこの情報には、たとえば、文書のスクロール位置、フォーム入力の値、および他のそのようなデータが含まれる場合があります。
  4. もし、新しい項目現在の項目と異なる Document オブジェクトを持っている場合は、その閲覧コンテキストは、その document プロパティが新しい項目によって参照される文書を参照するように更新され、コンテキストの名前は現在の文書のコンテキスト名と一致するように更新されます。
  5. 新しい項目Document 内の各フォームコントロールで、自動入力フィールド名が off に設定された autocomplete が設定されているものは、リセットされます。自動補完されるフィールド名や自動補完の仕組みについては HTML の自動補完を参照してください。
  6. 新しい項目の文書が既に完全に読み込まれ準備されている場合、つまり、その readyStatecomplete で、文書がまだ表示されていない場合、文書が表示され、 pageshow イベントは PageTransitionEventpersisted (en-US) 属性が true に設定された状態でその文書で発行されます。
  7. この文書の URL新しい項目のものに設定されます。
  8. 履歴の走査が置換を有効にして行われている場合、(go() などのメソッドの delta 引数を考慮して)目的の項目の直前の項目が履歴スタックから削除されます。
  9. もし新しい項目が持続的なユーザーの状態を持っておらず、その URL のフラグメントが null でなければ、その文書はそのフラグメントまでスクロールされます。
  10. 次に、現在の項目新しい項目に設定されます。宛先の項目は現在のものであると認識されます。
  11. 新しい項目 にシリアライズされた状態情報が保存されている場合、その情報は History.state にデシリアライズされます。それ以外の場合は statenull となる。
  12. state の値が変化した場合、文書に popstate イベントが送信されます。
  13. ブラウザーが選択した場合、永続化されたユーザー状態が復元されます。
  14. 元の項目と新しい項目が同じ文書を共有しているが、 URL のフラグメントが異なる場合、 hashchange イベントをウィンドウに送ります。

ご覧の通り、popstate イベントは、この方法でページ間を移動する過程で、ほぼ最後に発行されます。

http://example.com/example.html にあるページで以下のコードを実行すると、書かれている通りのログを出力します。

js
window.addEventListener("popstate", (event) => {
  console.log(
    `location: ${document.location}, state: ${JSON.stringify(event.state)}`,
  );
});
history.pushState({ page: 1 }, "title 1", "?page=1");
history.pushState({ page: 2 }, "title 2", "?page=2");
history.replaceState({ page: 3 }, "title 3", "?page=3");
history.back(); // "location: http://example.com/example.html?page=1, state: {"page":1}" と出力
history.back(); // "location: http://example.com/example.html, state: null" と出力
history.go(2); // "location: http://example.com/example.html?page=3, state: {"page":3}" と出力

同じ例で、 onpopstate イベントハンドラープロパティを使用したものです。

js
window.onpopstate = (event) => {
  console.log(
    `location: ${document.location}, state: ${JSON.stringify(event.state)}`,
  );
};
history.pushState({ page: 1 }, "title 1", "?page=1");
history.pushState({ page: 2 }, "title 2", "?page=2");
history.replaceState({ page: 3 }, "title 3", "?page=3");
history.back(); // "location: http://example.com/example.html?page=1, state: {"page":1}" と出力
history.back(); // "location: http://example.com/example.html, state: null" と出力
history.go(2); // "location: http://example.com/example.html?page=3, state: {"page":3}" と出力

元のの履歴項目 (http://example.com/example.html) には、状態オブジェクトが関連付けられていませんが、 2 回目の history.back() の呼び出しの後にその項目をアクティブにすると、 popstate イベントが発生することに注意してください。

仕様書

Specification
HTML Standard
# event-popstate
HTML Standard
# handler-window-onpopstate

ブラウザーの互換性

BCD tables only load in the browser

関連情報