在單頁應用程式(SPA)的架構中,客戶端路由一直扮演著核心角色。然而,長期以來開發團隊在處理網頁跳轉、過渡動畫與歷史紀錄時,不得不仰賴已被視為過時的 History API。這套誕生於十餘年前的標準,不僅語意不夠直覺,在非同步處理與事件攔截上也存在許多技術限制。
隨著 Web 標準的演進,全新的 Navigation API 正式被列入 Web Baseline Newly Available 規範。這意味著所有主流常青瀏覽器的最新版本已全面支援此項功能,前端工程團隊得以用更簡潔、原生的方式重構 SPA 導覽邏輯,精簡原本為了相容舊版瀏覽器而打包的大量 Polyfill。若想深入了解如何透過 Web Baseline 精簡前端專案,可參考我們先前提及的 善用Web Baseline精簡網站前端程式碼提升載入速度 指南。
傳統 History API 在單頁應用導覽中的局限性
在評估新技術之前,必須先釐清現有工具的技術缺陷。傳統的 History API(包含 window.history 與 popstate 事件)並不是為了現代單頁應用程式的「虛擬導覽」而設計的。它最主要的痛點在於無法全面攔截導覽行為。
舉例來說,當使用者點擊網頁上的 <a> 標籤時,瀏覽器預設會發送 HTTP 請求並重新整理頁面。為了維持 SPA 的流暢體驗,前端框架(如 React Router 或 Vue Router)通常需要實作複雜的事件委派機制,監聽全域的點擊事件,判斷該連結是否為同源跳轉,然後手動呼叫 event.preventDefault(),再執行 history.pushState()。更棘手的是,pushState() 與 replaceState() 的呼叫本身並不會觸發 popstate 事件,這導致狀態同步邏輯異常破碎。
什麼是 Navigation API 及其解決的核心痛點
與傳統機制相比,Navigation API 是專門為 SPA 客戶端路由設計的現代化介面。根據 Navigation API on web.dev 官方發布的技術細節,這項規格將原本分散在點擊監聽、歷史紀錄異動與表單提交的邏輯,統一收攏至單一事件流中。
其核心優勢在於引入了集中式的 navigate 事件。無論導覽是由程式碼驅動、用戶點擊連結、提交表單,還是點擊瀏覽器的「上一頁」與「下一頁」按鈕,都會觸發同一個監聽器。這免去了開發者重複撰寫點擊攔截邏輯的負擔,也提供了一致的非同步生命週期管理。
Navigation API 與 History API 的語意與結構對照
為了清楚呈現技術演進,下方整理了兩套 API 在實務開發維度上的差異:
| 功能維度 | 傳統 History API | 現代 Navigation API |
|---|---|---|
| 事件監聽範圍 | 僅限歷史紀錄倒退與前進(不包含程式發起的變更) | 涵蓋所有類型的導覽(點擊、程式觸發、歷史瀏覽、表單提交) |
| 非同步導覽控制 | 難以原生追蹤,必須自行包裝 Promise 進行狀態維護 | 支援傳遞 Promise 進行非同步過渡與載入狀態管理 |
| 歷史紀錄狀態追蹤 | state 結構受限,缺乏唯一的 Key 進行項目比對 | 提供 currentEntry 屬性,具備唯一 ID 與快照機制 |
| 重導向處理 | 需要手動介入管理歷史堆疊,極易產生無效頁面記錄 | 提供原生的重導向支持,並自動修正歷史紀錄軌跡 |
如何為 SPA 專案安全導入 Navigation API
要在專案中實作 Navigation API 並確保穩定運作,建議遵循以下步驟,以漸進增強(Progressive Enhancement)的方式進行整合:
- 環境支援度檢查:首先檢測當前瀏覽器是否已原生支持
window.navigation物件。若不支援,則優雅降級至傳統路由邏輯。 - 註冊全域 navigate 事件:建立全域的監聽器來接收所有導覽訊號,並透過
shouldIntercept屬性判斷該導覽是否屬於同源的 SPA 跳轉。 - 執行 intercept() 攔截:當確認為內部跳轉時,呼叫
event.intercept()。此方法會阻止瀏覽器的預設跳轉行為,並允許傳入一個返回 Promise 的非同步回呼函式(handler),用於載入新組件或獲取 API 數據。
以下是基礎的實作程式碼範例:
if (window.navigation) {
navigation.addEventListener('navigate', (event) => {
// 忽略跨域、下載連結或已取消的導覽
if (!event.canIntercept || event.hashChange || event.downloadRequest !== null) {
return;
}
const url = new URL(event.destination.url);
if (url.origin !== location.origin) {
return;
}
// 攔截並使用自訂邏輯載入頁面
event.intercept({
async handler() {
// 模擬非同步讀取元件與資料
await loadPageContent(url.pathname);
document.title = getPageTitle(url.pathname);
}
});
});
}Navigation API 的實務限制與相容性例外情境
儘管 Navigation API 提供了強大的開發體驗改善,但在實務佈署時,仍有兩大不可忽略的例外與限制,開發團隊必須做好妥善的因應對策:
例外情境一:舊版與非標準瀏覽器之相容性斷層。雖然該 API 已經進入 Web Baseline Newly Available 階段,但這僅代表「最新常青版本」支援。在企業級應用中,仍有相當高比例的使用者停留在舊版作業系統或未隨之更新的行動端瀏覽器。在這些環境下,直接呼叫 window.navigation 會導致執行階段錯誤(Runtime Error)。因此,專案中必須保留相容舊版 History API 的底層備份方案,切勿直接全面移除舊有路由程式碼。
例外情境二:跨網域跳轉與安全性沙盒限制。若導覽目的地涉及不同的子網域(Subdomain),或是頁面被嵌入於具有嚴格沙盒屬性(Sandbox Attributes)的 iframe 中,event.canIntercept 會自動返回 false。在此情況下,Navigation API 將無法實施事件攔截,瀏覽器仍會強制執行傳統的 Full Page Reload。開發團隊在規劃多系統單一登入(SSO)或跨域整合時,應特別留意此一安全性原則。
評估 Navigation API 對 Core Web Vitals 的潛在影響
從效能優化的角度來看,導入 Navigation API 對於關鍵體驗指標 Interaction to Next Paint (INP) 有著間接的正面影響。傳統路由在點擊連結後,由於需要執行密集的 DOM 移除、掛載、重繪,以及非同步資料抓取,容易阻塞主執行緒,導致使用者點擊後產生明顯的畫面停頓。
Navigation API 藉由內建的非同步 handler 機制,讓瀏覽器得以提早得知該導覽正在處理中。這使得瀏覽器能更智慧地調配渲染時機,甚至在背景載入資源時維持當前頁面的可互動性,待 Promise 履行後再進行無縫替換,進而優化前端的響應速度與互動流暢度。
在實施重構時,建議開發者採用漸進增強策略,一方面享受原生 Navigation API 帶來的簡潔程式碼與良好體驗,另一方面持續維護必要的降級備援機制,確保各類瀏覽環境皆能穩健運作。