平常使用 Angular Router 時,可以透過 routerLink 或 router.navigate() 切換不同頁面。
模板連結:
<a routerLink="/users">使用者</a>
程式導向:
router.navigate(['/users']);
網址會改變,畫面也會跟著切換,但整個 Angular Application 並不會重新載入。
不過瀏覽器原本的頁面導覽並不是這樣運作的。如果直接修改 window.location:
window.location.href = '/users';
瀏覽器會真正前往新的 URL,離開目前的 Document,再向 Server 請求新的頁面。HTML、JavaScript、CSS 等資源也可能重新載入,Application 也會重新建立。
這種方式很適合傳統的 Multi-Page Application,但 SPA 希望在 URL 改變時保留目前的 Document,只更新需要切換的畫面,因此需要另一種管理 URL 與瀏覽紀錄的方式。
History API 提供幾個常見方法:
// 新增一筆瀏覽紀錄,網址切換成 /users
history.pushState({}, '', '/users');
// 取代目前這筆瀏覽紀錄,不會新增新的 History Entry
history.replaceState({}, '', '/profile');
// 回到上一筆瀏覽紀錄
history.back();
// 前往下一筆瀏覽紀錄
history.forward();
例如:
history.pushState({}, '', '/users');
網址會變成 /users,但目前的 Document 不會重新載入,這也是 SPA Router 能運作的重要基礎。
不過 pushState() 只負責建立新的 History Entry,它不知道 Angular 接下來要顯示哪個 Component。Angular Router 還需要根據目前的 URL 比對 Route,執行對應的導覽並更新畫面。
使用者也可能透過瀏覽器的上一頁或下一頁切換位置。這時 Browser 會改變目前的 History Entry,並觸發 popstate:
window.addEventListener('popstate', () => {
console.log(location.pathname);
});
Angular Router 監聽到這類變化後,再根據目前的 URL 執行對應的 Navigation。
傳統 SPA Router 便是透過 History API、popstate 與 Router 本身的導覽機制,同時處理程式導向與瀏覽器的上一頁、下一頁。

History API 可以新增、取代或切換 History Entry,但不會描述 Angular Router 內部的導覽狀態。
例如:
router.navigate(['/users']);
Router 開始處理這次 Navigation 後,中間仍可能被取消,或在載入過程中發生錯誤。
Angular Router 本身就有對應的 Navigation Event:
// Navigation 開始
NavigationStart
// Navigation 成功完成
NavigationEnd
// Navigation 被取消,例如 Guard 阻擋
NavigationCancel
// Navigation 過程發生錯誤
NavigationError
History API 知道瀏覽紀錄發生了變化,卻不知道 Router Navigation 最後是成功、取消還是失敗,這些狀態仍然要由 Router 自己管理。
Navigation API 則把 Navigation 本身帶進 Browser 的原生模型中。
Navigation API 的入口是:
window.navigation
可以直接執行導覽:
navigation.navigate('/users');
也可以監聽 Navigation:
navigation.addEventListener('navigate', event => {
console.log(event.destination.url);
});
使用者點擊連結、按下 Back / Forward,或程式主動執行 Navigation 時,都可以透過 navigate Event 取得這次導覽的資訊。
History API 著重在 History Entry 的操作;Navigation API 則讓 Browser 能直接掌握一次 Navigation 的發生與狀態。
Navigation API 提供 intercept(),讓 Application 可以接手這次導覽。
假設頁面中有一般的連結:
<a href="/users">使用者</a>
正常情況下,Browser 會前往 /users 並載入新的 Document。
透過 Navigation API,可以在 navigate 發生時攔截:
navigation.addEventListener('navigate', event => {
event.intercept({
async handler() {
await renderPage();
}
});
});
Browser 仍然知道使用者正在前往 /users,但 Application 可以接手後續處理,在目前的 Document 中更新畫面,不需要重新載入整個頁面。
過去 SPA 通常需要監聽 Link Click、阻止預設行為,再透過 History API 修改 URL;Navigation API 則提供統一的 Navigation Event,讓不同的導覽來源可以從同一套機制處理。
Navigation API 也可以取得目前的 History Entry:
navigation.currentEntry;
或取得目前這個分頁中可存取的同源 History Entries:
navigation.entries();
每一筆都是 NavigationHistoryEntry,包含 URL、索引、識別資訊與 State。
Navigation 的成功與失敗也有對應事件:
navigation.addEventListener('navigatesuccess', () => {
console.log('Navigation completed');
});
navigation.addEventListener('navigateerror', () => {
console.log('Navigation failed');
});
使用 navigate() 時,還可以取得這次導覽的兩個階段:
const result = navigation.navigate('/users');
await result.committed;
await result.finished;
committed:瀏覽器已經切換到新的 History Entry。finished:這次 Navigation 相關的處理已經完成。Navigation API 也包含換頁後的 Scroll 與 Focus 行為。如果 Application 想自行控制,可以在 intercept() 中設定:
navigation.addEventListener('navigate', event => {
event.intercept({
scroll: 'manual',
focusReset: 'manual',
async handler() {
await renderPage();
window.scrollTo({
top: 0
});
document.querySelector('h1')?.focus();
}
});
});
scroll: 'manual':捲動位置改由 Application 自己處理。focusReset: 'manual':不讓 Browser 自動重設焦點。這些屬於 Browser Navigation 的處理範圍;Angular Application 要顯示哪個畫面,以及 Route 是否能成功啟用,仍然是 Angular Router 的工作。

Navigation API 並不會取代 Angular Router。
Browser 可以處理 URL、History Entry 與 Navigation Lifecycle,但它不知道 Angular 的 Route 設定代表什麼:
{
path: 'users/:id',
component: UserDetailComponent
}
Route Matching、Component Activation,以及 Angular Application 內部的導覽規則,仍然由 Router 處理。
Angular 提供:
import {
provideRouter,
withExperimentalPlatformNavigation
} from '@angular/router';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(
routes,
withExperimentalPlatformNavigation()
)
]
});
withExperimentalPlatformNavigation() 讓 Angular Router 可以嘗試使用 Browser Navigation API。
這個功能從 Angular 21.1 開始提供,目前在 Angular 22 仍屬於實驗功能,比較適合用來了解 Router 未來可能採用的底層 Navigation 模型,而不是直接導入正式環境。
在連結寫法上也會有所不同:
<!-- 傳統 Angular Router -->
<a routerLink="/users">使用者</a>
<!-- Platform Navigation -->
<a href="/users">使用者</a>
差別在於 Navigation 從哪裡進入 Router。routerLink 直接由 Angular 發起導覽;Platform Navigation 則先由 Browser 辨識這次 Navigation,再交給 Angular Router 處理 Application Routing。
Angular Router 本來就有自己的 Scroll Restoration 機制,withInMemoryScrolling() 並不是 Navigation API 出現後才新增的功能。
例如:
import {
provideRouter,
withExperimentalPlatformNavigation,
withInMemoryScrolling
} from '@angular/router';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(
routes,
withExperimentalPlatformNavigation(),
withInMemoryScrolling({
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled'
})
)
]
});
兩個 Feature 處理的是不同層次:
withExperimentalPlatformNavigation():改變 Angular Router 與 Browser Navigation 的整合方式。withInMemoryScrolling():負責 Angular Router 本身的 Scroll Restoration。scrollPositionRestoration: 'enabled' 會在一般新的 Navigation 後回到頁面頂端,Back / Forward 則恢復先前記錄的捲動位置。
anchorScrolling: 'enabled' 則處理 URL Fragment,例如:
/users#profile
頁面中有:
<section id="profile">
...
</section>
Router 可以在導覽後捲到對應的位置。
這裡處理的是整個頁面的 Viewport Scroll。如果畫面裡還有自己的 Scroll Container,例如設定 overflow: auto 的 Table 區塊,裡面的 scrollTop 不會由 withInMemoryScrolling() 自動保存。
在使用 Platform Navigation 時,單次 Navigation 還可以透過 NavigationBehaviorOptions 控制 Scroll:
router.navigate(['/users'], {
scroll: 'manual'
});
scroll 主要有兩種設定:
after-transition:Navigation 完成後,按照 Router 的 Scroll Restoration 設定處理。manual:這次 Navigation 不讓 Router 自動處理 Scroll。因此 withInMemoryScrolling() 定義 Router 平常怎麼處理 Scroll,而 NavigationBehaviorOptions.scroll 則控制這一次 Navigation 是否交給 Router 自動處理。
例如:
router.navigate(['/users'], {
scroll: 'manual'
});
這次導覽就不會套用 Router 的 Scroll Restoration,後續的捲動位置改由 Application 自己處理。

window.location 會讓瀏覽器真正前往新的頁面,而 History API 讓 SPA 可以在不重新載入 Document 的情況下修改 URL,再由 Angular Router 更新對應畫面。
History API 主要處理瀏覽紀錄,完整的 Navigation 狀態仍需要 Router 自己管理。Navigation API 則把 Navigation 帶進 Browser 的原生模型中,讓導覽可以被監聽、攔截,也能取得完成與失敗狀態。
Angular Router 仍然負責 Application 內部的 Routing,而 Browser Navigation、History Entry、Scroll 與 Focus 等行為,則可以和 Web Platform 有更直接的整合。
withExperimentalPlatformNavigation() 目前仍屬於實驗功能,不適合直接當成正式環境的預設方案,但它提供了一個方向:Angular Router 不需要自己包辦所有 Browser Navigation 細節,而是能逐步建立在瀏覽器原生的 Navigation 能力上。
pushState() 與 popstate 的行為。navigate 事件、History Entry 與導覽狀態。scroll、focusReset 選項。NavigationStart 等 Router 事件。scroll 等設定。withExperimentalPlatformNavigation() 自 21.1 起標為實驗功能。