Window: popstate 事件

Baseline 已廣泛支援

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

當用戶瀏覽會話歷史記錄時,活動歷史記錄條目發生變化時,Window 介面的 popstate 事件會被觸發。它會將當前歷史記錄條目更改為使用者訪問的上一頁的條目,或者,如果使用 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() 方法呼叫,以有效地將其內部處理的回撥函式放在瀏覽器事件迴圈的末尾:window.onpopstate = () => setTimeout(doSomeThing, 0);

popstate 何時傳送

首先理解,為了對抗不需要的彈出視窗,除非頁面已經進行過互動,否則瀏覽器可能根本不會觸發 popstate 事件,這一點很重要。

本節描述了瀏覽器在確實可能觸發 popstate 事件的情況下(即頁面已進行互動的情況下)所遵循的步驟。

當發生導航時——無論是由於使用者觸發瀏覽器的 後退 按鈕還是其他原因——popstate 事件是在導航到新位置的過程接近尾聲時發生的。它發生在載入(如果需要)、顯示、可見等新位置之後——在傳送 pageshow 事件之後,但在恢復持久使用者狀態資訊和傳送 hashchange 事件之前。

為了更好地理解 popstate 事件何時觸發,請考慮噹噹前歷史記錄條目由於使用者導航網站或透過程式設計遍歷歷史記錄而更改時發生的簡化事件序列。在這裡,轉換正在將當前歷史記錄條目更改為我們將其稱為 new-entry 的條目。當前頁面的會話歷史記錄堆疊條目將被稱為 current-entry

  1. 如果 new-entry 當前不包含現有的 Document,則在繼續之前獲取內容並建立其 Document。這最終會向包含文件的 Window 傳送諸如 DOMContentLoadedload 等事件,但在此期間,以下步驟將繼續執行。
  2. 如果 current-entry 的標題未使用歷史記錄 API 方法之一(pushState()replaceState())設定,則將其標題設定為其 document.title 屬性返回的字串。
  3. 如果瀏覽器在離開 current-entry 之前希望儲存與 current-entry 相關的狀態資訊,它會這樣做。該條目現在被稱為具有“持久使用者狀態”。瀏覽器可能新增到歷史記錄會話條目的資訊可能包括,例如,文件的滾動位置、表單輸入的 S值以及其他此類資料。
  4. 如果 new-entry 具有與 current-entry 不同的 Document 物件,則更新瀏覽上下文,使其 document 屬性引用 new-entry 引用的文件,並且更新上下文的名稱以匹配當前文件的上下文名稱。
  5. new-entryDocument 中每個將 autocomplete 配置為自動填充欄位名稱設定為 off 的表單控制元件都將被重置。有關自動填充欄位名稱以及自動填充工作原理的更多資訊,請參閱 HTML autocomplete 屬性
  6. 如果 new-entry 的文件已完全載入並準備就緒——也就是說,它的 readyStatecomplete——並且文件尚未可見,則使其可見,並向文件觸發 pageshow 事件,其中 PageTransitionEventpersisted 屬性設定為 true
  7. 文件的 URL 設定為 new-entry 的 URL。
  8. 如果正在執行的遍歷歷史記錄已啟用替換,則目標條目緊接之前的條目(考慮到 go() 等方法上的 delta 引數)將從歷史記錄堆疊中刪除。
  9. 如果 new-entry 沒有持久使用者狀態,並且其 URL 的片段非 null,則文件滾動到該片段。
  10. 接下來,current-entry 設定為 new-entry。目標條目現在被認為是當前條目。
  11. 如果 new-entry 儲存了序列化狀態資訊,則該資訊被反序列化到 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(); // Logs "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // Logs "location: http://example.com/example.html, state: null"
history.go(2); // Logs "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(); // Logs "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // Logs "location: http://example.com/example.html, state: null"
history.go(2); // Logs "location: http://example.com/example.html?page=3, state: {"page":3}"

請注意,即使原始歷史記錄條目(針對 http://example.com/example.html)沒有與其關聯的狀態物件,但在第二次呼叫 history.back() 之後啟用該條目時,仍然會觸發 popstate 事件。

規範

規範
HTML
# event-popstate
HTML
# handler-window-onpopstate

瀏覽器相容性

另見