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 的規格包含許多專門給網頁開發人員的資訊。