Window: popstate イベント
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
popstate
は Window
インターフェイスのイベントで、ユーザーがセッション履歴を操作している間にアクティブな履歴項目が変更されたときに発行されます。これは現在の履歴項目をユーザーが最後に訪れたページのものに変更するか、または history.pushState()
が履歴項目を履歴スタックに追加するために使用されていた場合、その履歴項目が代わりに使用されます。
構文
このイベント名を addEventListener()
などのメソッドで使用するか、イベントハンドラープロパティを設定するかしてください。
addEventListener("popstate", (event) => {});
onpopstate = (event) => {};
イベント型
PopStateEvent
です。 Event
を継承しています。
イベントプロパティ
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
イベントが発行されるタイミングをよりよく理解するために、ユーザーがサイトを移動するか、履歴をプログラムで走査することによって、現在の履歴項目が変更されたときに発行されるイベントのシーケンスを単純化して考えてみましょう。ここでは、現在の履歴項目を新しい項目と呼ぶものに変更する遷移を示します。現在のページのセッション履歴スタック項目は現在の項目と呼びます。
- もし新しい項目 が現在、既存の
Document
を含んでいなければ、続行する前にコンテンツを取得し、そのDocument
を作成します。これはDOMContentLoaded
やload
イベントを最終的に文書を含むWindow
に送信しますが、以下のステップはその間に実行され続けます。 - 現在の項目のタイトルが履歴 API のメソッド、 (
pushState()
またはreplaceState()
) の何れかで設定されなかった場合は、その項目のタイトルがdocument.title
属性が返す文字列に設定されます。 - もし、ブラウザーが現在の項目から離れる前に保存したい状態情報を持っている場合は、保存します。このとき、その項目は「ユーザーの状態を保持した」とみなされます。ブラウザーが履歴セッションの項目に追加する可能性のあるこの情報には、たとえば、文書のスクロール位置、フォーム入力の値、および他のそのようなデータが含まれる場合があります。
- もし、新しい項目が現在の項目と異なる
Document
オブジェクトを持っている場合は、その閲覧コンテキストは、そのdocument
プロパティが新しい項目によって参照される文書を参照するように更新され、コンテキストの名前は現在の文書のコンテキスト名と一致するように更新されます。 - 新しい項目の
Document
内の各フォームコントロールで、自動入力フィールド名がoff
に設定されたautocomplete
が設定されているものは、リセットされます。自動補完されるフィールド名や自動補完の仕組みについては HTML の自動補完を参照してください。 - 新しい項目の文書が既に完全に読み込まれ準備されている場合、つまり、その
readyState
がcomplete
で、文書がまだ表示されていない場合、文書が表示され、pageshow
イベントはPageTransitionEvent
のpersisted
属性がtrue
に設定された状態でその文書で発行されます。 - この文書の
URL
が新しい項目のものに設定されます。 - 履歴の走査が置換を有効にして行われている場合、(
go()
などのメソッドのdelta
引数を考慮して)目的の項目の直前の項目が履歴スタックから削除されます。 - もし新しい項目が持続的なユーザーの状態を持っておらず、その URL のフラグメントが
null
でなければ、その文書はそのフラグメントまでスクロールされます。 - 次に、現在の項目が新しい項目に設定されます。宛先の項目は現在のものであると認識されます。
- 新しい項目 にシリアライズされた状態情報が保存されている場合、その情報は
History.state
にデシリアライズされます。それ以外の場合はstate
はnull
となる。 state
の値が変化した場合、文書にpopstate
イベントが送信されます。- ブラウザーが選択した場合、永続化されたユーザー状態が復元されます。
- 元の項目と新しい項目が同じ文書を共有しているが、 URL のフラグメントが異なる場合、
hashchange
イベントをウィンドウに送ります。
ご覧の通り、popstate
イベントは、この方法でページ間を移動する過程で、ほぼ最後に発行されます。
例
http://example.com/example.html
にあるページで以下のコードを実行すると、書かれている通りのログを出力します。
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
イベントハンドラープロパティを使用したものです。
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