Chrome 105 在 Navigation API 的 NavigateEvent 中推出了兩種新方法 (在 102 版推出),以改善在實際操作中已證實有問題的方法。intercept() 可讓開發人員控制導覽後的狀態,取代難以使用的 transitionWhile()。scroll() 方法會捲動至網址中指定的錨點,取代無法用於所有導覽類型的 restoreScroll()。
本文將說明這兩種方法的問題,以及新方法如何解決這些問題。
NavigateEvent.transitionWhile()
NavigateEvent.trasitionWhile() 方法是在 Chrome 102 中與 Navigation API 一併推出,可攔截單頁應用程式中用於用戶端轉場的導覽。其第一個引數是承諾,可向瀏覽器和網頁應用程式的其他部分傳送已完成的訊號。
但實際上效果不佳。請參考以下常見的程式設計模式:
event.transitionWhile((async () => {
doSyncStuff();
await doAsyncStuff();
})());
這與下列程式碼的功能相同。這會導致部分導覽作業在 API 察覺開發人員打算攔截導覽之前就執行。
doSyncStuff();
event.transitionWhile((async () => {
await doAsyncStuff();
})());
這可能會導致捲動還原邏輯擷取 DOM 變更後的捲動位置,而非擷取變更前的捲動位置,進而導致應用程式發生錯誤。
異動情形
為了取代 transitionWhile(),目前的規格引入了 NavigateEvent.intercept()。除了 transitionWhile() 支援的 focusReset 和 scrollRestoration 屬性外,新方法還會採用處理常式。新的處理常式一律會在導覽提交後執行,並擷取捲動位置等內容,避免 transitionWhile() 發生問題。
transitionWhile() 方法仍可使用,但已遭淘汰,並將在 Chrome 108 中移除。
使用 intercept()
NavigateEvent.intercept() 與 transitionWhile() 有相同的限制,也就是無法在所有導覽事件中呼叫。無法攔截跨來源導覽,也無法攔截跨文件的檢索作業。這麼做會擲回 "SecurityError" 類型的 DOMException。
如要使用 intercept(),請在呼叫時傳遞自訂處理常式。
navigation.addEventListener("navigate", event => {
event.intercept({
async handler() {
doSyncStuff();
await doAsyncStuff();
}
});
});
NavigateEvent.scroll()
即使是在單頁應用程式中,瀏覽器也會完全處理導覽作業,例如從網頁頂端前往錨點 (從 /a 移動到 /a#id)。不過,如果要前往另一個「頁面」上的錨點 (從 /a 移動到 /b#id),雖然在多頁應用程式中很簡單,但在單頁應用程式中則較為複雜。應用程式必須使用 NavigateEvent.transitionWhile() 攔截導向 /b#id 的導覽,然後呼叫 NavigateEvent.restoreScroll() 將錨點帶入檢視畫面。如上所述,目前很難做到這點。
異動情形
在單頁應用程式中,您現在可以控制瀏覽器是否要處理捲動至錨點的動作,或是由程式碼處理。
使用 scroll()
根據預設,一旦攔截處理程序完成,瀏覽器就會嘗試自動處理捲動作業。如果您想自行處理捲動,請將 scroll 設為 "manual",然後在瀏覽器嘗試設定捲動位置時呼叫 NavigateEvent.scroll()。
navigation.addEventListener("manual", event => {
scroll: "manual",
event.intercept({
async handler() {
doSyncStuff();
// Handle scrolling earlier than by default:
event.scroll();
await doAsyncStuff();
}
});
});
restoreScroll() 方法仍可使用,但已遭淘汰,並將在 Chrome 108 中移除。
結論
我們希望能盡快更新 Navigation API 相關文章。在此期間,這個 API 的規格包含許多專門為網頁開發人員提供的資訊。