文章目錄
- 概念
- 全局路由守衛
- 全局前置守衛
- 全局解析守衛
- 全局后置路由守衛
- 獨享路由守衛
- 組件內的守衛
- beforeRouteEnter
- beforeRouteUpdate
- beforeRouteLeave
- 完整的導航解析流程
上一篇:(四十六)Vue Router組件所獨有的兩個鉤子activate、deactivated
概念
路由守衛是在前端應用中用于控制和管理路由導航的機制。它們允許開發人員在路由導航事件發生之前或之后執行一些邏輯。
路由守衛可以用于實現以下功能:
- 身份驗證:通過在路由導航之前檢查用戶的身份驗證狀態,可以防止未經授權的用戶訪問受保護的頁面。如果用戶未登錄或沒有足夠的權限,可以重定向到登錄頁面或顯示適當的提示信息。
- 授權:除了身份驗證外,路由守衛還可以檢查用戶是否具有足夠的權限訪問某個頁面或執行某個操作。如果用戶權限不足,可以阻止導航或采取其他適當的措施。
- 數據預加載:在加載某個路由之前,可以使用路由守衛來預加載所需的數據。這可以提高用戶體驗,減少頁面加載時間,并確保頁面所需的數據在渲染之前已經準備好。
全局路由守衛
全局路由守衛是應用于整個路由系統的守衛機制。它們會在每次路由導航事件發生時觸發,并允許開發人員執行一些全局級別的邏輯。
每個守衛方法接收三個參數:
to: Route
:即將要進入的目標 路由對象from: Route
:當前導航正要離開的路由next: Function
::一定要調用該方法來 resolve 這個鉤子。執行效果依賴 next 方法的調用參數。next()
::進行管道中的下一個鉤子。如果全部鉤子執行完了,則導航的狀態就是 confirmed (確認的)。next(false)
: 中斷當前的導航。如果瀏覽器的 URL 改變了 (可能是用戶手動或者瀏覽器后退按鈕),那么 URL 地址會重置到from 路由對應的地址。next('/')
或者next({ path: '/' })
: 跳轉到一個不同的地址。當前的導航被中斷,然后進行一個新的導航。你可以向 next 傳遞任意位置對象,且允許設置諸如 replace: true、name: ‘home’ 之類的選項以及任何用在 router-link 的 to prop 或 router.push 中的選項。next(error):
:(2.4.0+) 如果傳入 next 的參數是一個 Error 實例,則導航會被終止且該錯誤會被傳遞給 router.onError() 注冊過的回調。
確保 next 函數在任何給定的導航守衛中都被嚴格調用一次。它可以出現多于一次,但是只能在所有的邏輯路徑都不重疊的情況下,否則鉤子永遠都不會被解析或報錯。
這里有一個在用戶未能驗證身份時重定向到 /login 的示例:
// BAD
router.beforeEach((to, from, next) => {if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })// 如果用戶未能驗證身份,則 `next` 會被調用兩次next()
})
// GOOD
router.beforeEach((to, from, next) => {if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })else next()
})
全局路由守衛分類:
- 全局前置路由守衛
- 全局解析路由守衛
- 全局后置路由守衛
執行順序:
- 全局前置路由守衛 (beforeEach)按照注冊順序執行。
- 解析路由守衛 (beforeResolve)按照注冊順序執行。
- 路由組件實例化和渲染。
- 全局后置路由守衛 (afterEach)按照注冊順序執行。
全局前置守衛
當一個導航觸發時,初始化的時候和每次路由切換之前調用,全局前置守衛按照創建順序調用。守衛是異步解析執行,此時導航在所有守衛 resolve 完之前一直處于等待中。
你可以使用 router.beforeEach 注冊一個全局前置守衛:
const router = new VueRouter({ ... })//全局前置路由守衛---初始化的時候和每次路由切換之前調用
router.beforeEach((to, from, next) => {// ...
})
全局解析守衛
全局解析守衛是一個在路由導航之前觸發的守衛機制,用于在路由進入組件之前預加載所需的數據。它可以在整個路由系統中應用,確保數據在組件渲染之前已經準備好。
const router = new VueRouter({ ... })router.beforeResolve((to, from, next) => {// 在路由導航之前觸發,可以執行解析邏輯或其他操作// 在這里可以預加載數據或執行其他全局級別的處理next(); // 確保繼續路由導航
});
全局后置路由守衛
全局后置路由守衛是Vue Router中的一種路由守衛,用于在路由導航完成后執行一些操作。它可以用于記錄頁面訪問日志、執行統計分析或其他需要在路由導航后進行的全局級別處理。
和其他守衛不同的是,這些鉤子不會接受 next
函數也不會改變導航本身:
const router = new VueRouter({ ... })//全局后置路由守衛---初始化的時候和每次路由切換之后被調用
router.afterEach((to, from) => {// 在路由導航完成后觸發,可以執行一些操作// 在這里可以記錄頁面訪問日志、執行統計分析或其他全局級別的處理
});
獨享路由守衛
在Vue Router中,你可以使用全局獨享路由守衛來為特定的路由配置獨立的守衛。全局獨享路由守衛提供了更細粒度的控制,可以在特定路由上執行一些操作或驗證邏輯。全局獨享路由守衛可以通過在路由配置中的beforeEnter
字段中定義一個守衛函數來實現。
const router = new VueRouter({routes: [{path: '/xxx',component: xxx,beforeEnter: (to, from, next) => {// 在進入路由之前觸發,可以執行一些操作或驗證邏輯// 在這里可以進行身份驗證或其他特定路由級別的處理next(); // 確保繼續路由導航}},// 其他路由配置...]
});
組件內的守衛
可以在組件內部定義路由守衛,以便在特定組件中執行相關的操作或驗證邏輯。這種類型的守衛被稱為組件內的路由守衛(Component Guard)。Vue Router提供了以下幾種組件內的路由守衛:
- beforeRouteEnter:在進入路由之前被調用。它在組件實例被創建之前被調用,因此在該守衛中無法直接訪問組件實例
this
。 - beforeRouteUpdate(2.2 新增):在當前路由改變,但是該組件被復用時調用。它可以用于響應路由參數的變化,以及在組件復用時執行一些邏輯。可以訪問組件實例
this
- beforeRouteLeave:在離開當前路由之前被調用。可以用于確認是否離開當前頁面、保存表單等操作。可以訪問組件實例
this
beforeRouteEnter
beforeRouteEnter 守衛 不能 訪問 this,因為守衛在導航確認前被調用,因此即將登場的新組件還沒被創建。
不過,你可以通過傳一個回調給 next來訪問組件實例。在導航被確認的時候執行回調,并且把組件實例作為回調方法的參數。
beforeRouteEnter (to, from, next) {next(vm => {// 通過 `vm` 訪問組件實例})
}
注意 beforeRouteEnter
是支持給 next
傳遞回調的唯一守衛。對于 beforeRouteUpdate
和 beforeRouteLeave
來說,this
已經可用了,所以不支持傳遞回調,因為沒有必要了。
beforeRouteUpdate
在當前路由改變,但是該組件被復用時調用,舉例來說,對于一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2
之間跳轉的時候,由于會渲染同樣的 Foo 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用。
beforeRouteUpdate (to, from, next) {// 可以使用 `this`
}
beforeRouteLeave
導航離開該組件的對應路由時調用
beforeRouteLeave(to, from, next) {// 可以訪問組件實例 `this`
}
完整的導航解析流程
- 導航被觸發。
- 在失活的組件里調用
beforeRouteLeave
守衛。 - 調用全局的
beforeEach
守衛。 - 在重用的組件里調用
beforeRouteUpdate
守衛 (2.2+)。 - 在路由配置里調用
beforeEnter
。 - 解析異步路由組件。
- 在被激活的組件里調用
beforeRouteEnter
。 - 調用全局的
beforeResolve
守衛 (2.5+)。 - 導航被確認。
- 調用全局的
afterEach
鉤子。 - 觸發 DOM 更新。
- 調用
beforeRouteEnter
守衛中傳給next
的回調函數,創建好的組件實例會作為回調函數的參數傳入。