Vue-5 路由傳參的幾種方式(query和params),獲取路由參數,導航守衛和路由元信息,History模式
除了 props
和 $emit
之外,路由時也可以攜帶數據,即通過路由傳參。
一、路由參數的傳遞和接收
1. 動態路由的匹配
示例需求:有個商品詳情的組件,點擊任何商品都會渲染這個組件,點擊商品時向詳情組件傳遞商品的 id,詳情組件在被渲染時接收這個 id,請求對應的數據,渲染在詳情組件上。
可以在配置路由時直接爲參數預留路徑:
// router>index.js 的routes
routes: [
{
// 在路徑中預留參數的位置
path: '/good-detail/:id',
component: Detail
}
]
調用:
<!-- 調用路由時向路由傳參 -->
<router-link to="/good-detail/1">商品1</router-link>
<router-link to="/good-detail/2">商品2</router-link>
<router-link to="/good-detail/3">商品3</router-link>
<!-- 渲染詳情組件 -->
<router-view />
接收參數:
<!-- 詳情組件的結構中接收 -->
<div class="detail">
<!-- 用 $route 獲取路由信息,從路由信息的 params 中接收參數 -->
{{ this.$route.params.id }}
</div>
// 如果想要在組件剛開始加載時獲取 id,並且根據 id 做一些數據操作,那就在對應的鉤子函數中,獲取路由參數
created() { // detail 組件生命週期的 created 鉤子函數
const id = this.$route.params.id;
// code
}
用 created
和 mounted
函數,只能在第一個商品被渲染時響應,detail
組件在第一次被渲染之後,雖然路由變了,但是 created
和 mounted
不會重新執行。這種情況下,可以用 updated
來動態獲取路由參數。也可以用 watch
來監聽路由的變化。
watch: {
// to 和 from 分別表示路由切換前後的路由元信息
'$route'(to, from) {
// 對路由變化作出響應...
}
}
2. router-link 的 to屬性傳參
如果使用 <router-link>
標籤的 to
屬性動態傳參,那麼路由配置時不需要在 path
路徑中預留參數的位置,直接傳參並接收就可以了。
// router>index.js 的routes
routes: [
{
// 路徑中不需要預留參數的位置
path: '/good-detail',
component: Detail
}
]
傳參:
<!--
to 動態傳參時,要傳一個對象,要綁定 v-bind 指令
路由中的參數有兩個列表,分別是 query 和 params
-->
<router-link
:to="{
path: '/good-detail',
query: {
id: 1
}
}"
>商品3</router-link>
接收參數:
// detail 組件的 created 鉤子函數
created() {
const id = this.$route.query.id;
// code
}
這樣傳參,有個好處,就是有多個參數時,無論是配置還是傳參,代碼都非常簡潔,如果有多個參數,直接列在 query
對象中就可以了。
但是也有個缺點,就是傳遞的參數會暴露在 url
中,如果參數中的信息是需要保護的信息,那麼直接暴露就沒有任何安全性了。
這就要用到 params
,params
和 query
的區別就是 params
中的參數不會暴露在 url
中,query
會。
但是 params
需要和路由的 name
結合使用。
// router>index.js 的routes
routes: [
{
path: '/good-detail',
name: 'good-detail',
component: Detail
}
]
<router-link
:to="{
name: 'good-detail',
params: {
id: 1
}
}"
>商品3</router-link>
獲取 params
中的參數:
// detail 組件的 created 鉤子函數
created() {
const id = this.$route.params.id;
// code
}
注:
path
只能和 query
結合使用,name
可以和 query
或者 params
結合使用,但是 name
和 query
結合使用時,參數依舊會暴露。
3. push 時傳參
// path 和 query 結合使用
this.$router.push({
path: '/good-detail',
query: {
id: 1
}
});
// name 和 query 結合使用
this.$router.push({
name: 'good-detail',
query: {
id: 1
}
});
// name 和 params 結合使用
this.$router.push({
path: '/good-detail',
params: {
id: 1
}
});
接受參數方式不變。
二、導航守衛和路由元信息
1. 導航守衛
通俗點說,導航守衛指在路由切換時,對組件中的數據或者用戶信息做一些保護和判斷。
比如用戶從 A 組件切換到 B 組件,但是 B 組件中的內容是要根據用戶的權限渲染的,不同權限的用戶渲染不同的內容。就需要在切換之前拿到用戶的權限信息,做判斷之後再切換組件。
還有一種可能性,某個後臺管理系統只能在用戶登錄之後才展示相對應的頁面,但是用戶可能已經知道了首頁的路徑,用戶可能沒經過登錄直接在瀏覽器輸入首頁路徑,要強行進入首頁,那麼在此之前,我們要做導航守衛。
其實我們可以把導航守衛理解成路由過程中的鉤子函數。
全局守衛
// router>index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const router = new Router({
routes: [
// ...
]
});
// 全局前置守衛
router.beforeEach((to, from, next) => {
// code
});
// 全局後置鉤子
router.afterEach((to, from) => {
// ...
});
export default router
全局的守衛會在每個路由發生變化時響應,但是有時候我們只需要在某個路由發生變化時做一些操作,並不需要所有路由全部響應切換。全局守衛的循環還是稍微有點耗性能。
某個路由自己的守衛
import Vue from 'vue'
import Router from 'vue-router'
import GoodDetail from '@/components/GoodDetail'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/good-detail',
component: GoodDetail,
beforeEnter: (to, from, next) => {
// 只有當前路由切換時要響應的代碼
// 和其他路由沒有任何關係
}
}
]
})
如果需要在某個組件中,捕獲到路由變化之後或者之前,對數據做一些保留或清除動作。
比如從商品列表切換到商品詳情,我們可以在詳情組件路由切換成功的鉤子函數中,獲取路由參數,就可以使用組件中的路由守衛(當然也可以用組件生命週期鉤子函數,也可以使用watch,這裏組件中的路由守衛只是提供另一種可能性)。
組件內的守衛
// 某個組件的 export
export default {
name: 'Detail',
// vue-router 文檔提供的示例
beforeRouteEnter (to, from, next) {
// 在渲染該組件的對應路由被 confirm 前調用
// 不!能!獲取組件實例 `this`
// 因爲當守衛執行前,組件實例還沒被創建
},
beforeRouteUpdate (to, from, next) {
// 在當前路由改變,但是該組件被複用時調用
// 舉例來說,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
// 由於會渲染同樣的 Foo 組件,因此組件實例會被複用。而這個鉤子就會在這個情況下被調用。
// 可以訪問組件實例 `this`
},
beforeRouteLeave (to, from, next) {
// 導航離開該組件的對應路由時調用
// 可以訪問組件實例 `this`
}
}
注:
beforeRouteEnter 守衛 不能 訪問 this,因爲守衛在導航確認前被調用,因此即將登場的新組件還沒被創建。
完整的導航流程解析
官網給了導航切換的整個細緻流程及每個階段的鉤子函數。
- 導航被觸發。
- 在失活的組件裏調用離開守衛。
- 調用全局的 beforeEach 守衛。
- 在重用的組件裏調用 beforeRouteUpdate 守衛 (2.2+)。
- 在路由配置裏調用 beforeEnter。
- 解析異步路由組件。
- 在被激活的組件裏調用 beforeRouteEnter。
- 調用全局的 beforeResolve 守衛 (2.5+)。
- 導航被確認。
- 調用全局的 afterEach 鉤子。
- 觸發 DOM 更新。
- 用創建好的實例調用 beforeRouteEnter 守衛中傳給 next 的回調函數。
to, from, next
在上面的很多例子中,我們都能看到 鉤子函數接收的參數,to,from,next。它們都代表特殊的意義和作用。
-
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() 註冊過的回調。
-
2. 路由元信息
在配置路由時,路由對應的某些固定數據,我們可以直接綁定在路由配置對象的 meta
對象中,然後在需要時獲取。
// router>index.js 的 routes
routes: [
{
path: '/good-detail',
component: GoodDetail,
// 定義路由的時候可以配置 meta 字段:
meta: {
title: '商品詳情',
ifSee: true
}
}
]
獲取路由元信息:
// Detail 組件的 created
created() {
console.log(this.$route.meta);
}
History 模式
我們在運行項目時,能看到 url
中帶有一個 #
,這個是 vue-router
默認的 hash 模式。因爲正常情況下,切換瀏覽器的 url
瀏覽器中的內容是要刷新的,但是我們希望的是通過在 url
中切換路由來實現頁面組件的切換,所以 vue-router
在 url
中添加了 #
號,這樣在切換路由導致 url
改變時不會刷新頁面。其實 <router-link>
標籤最終渲染的真實 DOM
是 <a>
,to
屬性是 <a>
標籤的 href
,#
是錨點:
<a data-v-957c9522="" href="#/good-detail" class="router-link-exact-active router-link-active">詳情</a>
如果不想要很醜的 hash,我們可以用路由的 history 模式,這種模式充分利用 history.pushState API 來完成 URL 跳轉而無須重新加載頁面。
const router = new VueRouter({
mode: 'history',
routes: [...]
})
當使用 history 模式時,URL 就像正常的 url,例如 http://yoursite.com/user/id。
只是設置成 history
之後,一些與後臺的數據交互需要依賴後臺配置。