一、路由簡介
1、什么是路由?
- ? 定義:路由就是根據不同的 URL 地址展示不同的內容或頁面。
- ? 通俗理解:路由就像是一個地圖,我們要去不同的地方,需要通過不同的路線進行導航。
2、路由的作用
- ? 單頁應用程序(SPA)中,路由可以實現不同視圖之間的無刷新切換,提升用戶體驗;
- ? 路由還可以實現頁面的認證和權限控制,保護用戶的隱私和安全;
- ? 路由還可以利用瀏覽器的前進與后退,幫助用戶更好地回到之前訪問過的頁面。
二、路由重定向
重定向的作用:將一個路由重定向到另一個路由上
router.js文件:
// 導入路由創建的相關方法
import {createRouter,createWebHashHistory} from 'vue-router'
// 導入vue組件
import Home from '../components/Home.vue'
import List from '../components/List.vue'
import Add from '../components/Add.vue'
import Update from '../components/Update.vue'
// 創建路由對象,聲明路由規則
const router = createRouter({
? ? history: createWebHashHistory(),
? ? routes:[
? ? ? ? {
? ? ? ? ? ? path:'/',
? ? ? ? ? ? components:{
? ? ? ? ? ? ? ? default:Home,
? ? ? ? ? ? ? ? homeView:Home
? ? ? ? ? ? } ? ? ?
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? path:'/list',
? ? ? ? ? ? components:{
? ? ? ? ? ? ? ? listView : List
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? path:'/showAll',
? ? ? ? ? ? // 重定向
? ? ? ? ? ? redirect :'/list'
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? path:'/add',
? ? ? ? ? ? components:{
? ? ? ? ? ? ? ? addView:Add
? ? ? ? ? ? }
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? path:'/update',
? ? ? ? ? ? components:{
? ? ? ? ? ? ? ? updateView:Update
? ? ? ? ? ? } ?
? ? ? ? },
? ? ]
})
// 對外暴露路由對象
export default router;
?
+ App.vue
```html
<script setup>
</script>
<template>
? ? <div>
? ? ? <h1>App頁面</h1>
? ? ? <hr/>
? ? ? ? <!-- 路由的連接 -->
? ? ? ? <router-link to="/">home頁</router-link> <br>
? ? ? ? <router-link to="/list">list頁</router-link> <br>
? ? ? ? <router-link to="/showAll">showAll頁</router-link> <br>
? ? ? ? <router-link to="/add">add頁</router-link> <br>
? ? ? ? <router-link to="/update">update頁</router-link> <br>
? ? ? <hr/>
? ? ? <!-- 路由連接對應視圖的展示位置 -->
? ? ? <hr>
? ? ? 默認展示位置:<router-view></router-view>
? ? ? <hr>
? ? ? Home視圖展示:<router-view name="homeView"></router-view>
? ? ? <hr>
? ? ? List視圖展示:<router-view name="listView"></router-view>
? ? ? <hr>
? ? ? Add視圖展示:<router-view name="addView"></router-view>
? ? ? <hr>
? ? ? Update視圖展示:<router-view name="updateView"></router-view>
? ? </div>
</template>
<style scoped>
</style>
三、編程式路由
普通路由(聲明式路由)
`<router-link to="/list">list頁</router-link> ?`這種路由,to中的內容目前是固定的,點擊后只能切換/list對象組件
> 編程式路由
+ 通過useRouter,動態決定向那個組件切換的路由
+ 這里的 `useRouter` 方法返回的是一個 router 對象,你可以用它來做如導航到新頁面、返回上一頁面等操作。
+ App.vue
``` html
<script setup type="module">
? import {useRouter} from 'vue-router'
? import {ref} from 'vue'
? //創建動態路由對象
? let router = useRouter()
? let ?routePath =ref('')
? let ?showList= ()=>{
? ? ? // 編程式路由
? ? ? // 直接push一個路徑
? ? ? router.push('/list')
? ? ? // 或者push一個帶有path屬性的對象
? ? ? //router.push({path:'/list'})
? }
</script>
<template>
? ? <div>
? ? ? <h1>App頁面</h1>
? ? ? <hr/>
? ? ? ? <!-- 路由的連接 -->
? ? ? ? <router-link to="/">home頁</router-link> <br>
? ? ? ? <router-link to="/list">list頁</router-link> <br>
? ? ? ? <router-link to="/showAll">showAll頁</router-link> <br>
? ? ? ? <router-link to="/add">add頁</router-link> <br>
? ? ? ? <router-link to="/update">update頁</router-link> <br>
//以上to后固定了訪問路徑的都是聲明式路由,不能動態修改
? ? ? ? <!-- 動態輸入路徑,點擊按鈕,觸發單擊事件的函數,在函數中通過編程式路由切換頁面 -->
? ? ? ? <button @click="showList()">showList</button> <br>
? ? ? <hr/>
? ? ? <!-- 路由連接對應視圖的展示位置 -->
? ? ? <hr>
? ? ? 默認展示位置:<router-view></router-view>
? ? ? <hr>
? ? ? Home視圖展示:<router-view name="homeView"></router-view>
? ? ? <hr>
? ? ? List視圖展示:<router-view name="listView"></router-view>
? ? ? <hr>
? ? ? Add視圖展示:<router-view name="addView"></router-view>
? ? ? <hr>
? ? ? Update視圖展示:<router-view name="updateView"></router-view>
? ? </div>
</template>
<style scoped>
</style>
四、路由傳參
1、路徑參數
?在路徑中使用一個動態字段來實現,我們稱之為路徑參數
? ? + 例如: 查看數據詳情 ?`/showDetail/1` ?,`1`就是要查看詳情的id,可以動態添值!
2、鍵值對參數
類似于get請求通過url傳參,數據是鍵值對形式的
? ? 例如: ?查看數據詳情`/showDetail?hid=1`,`hid=1`就是要傳遞的鍵值對參數
? ? ?在 Vue 3 和 Vue Router 4 中,可以使用 ?`useRoute` 這個函數從 Vue 的組合式 API 中獲取路由對象。
? ? + ?`useRoute` 方法返回的是當前的 route 對象,你可以用它來獲取關于當前路由的信息,如當前的路徑、查詢參數等。
對比:useRouter方法返回的是一個router對象,可以用于導航新頁面和返回上一個頁面。
> 案例需求 : 切換到ShowDetail.vue組件時,向該組件通過路由傳遞參數
修改App.vue文件
``` html
<script setup type="module">
? import {useRouter} from 'vue-router'
? //創建動態路由對象
? let router = useRouter()
? //動態路由路徑傳參方法
? let showDetail= (id,language)=>{
? ? ? // 嘗試使用拼接字符串方式傳遞路徑參數
? ? ? //router.push(`showDetail/${id}/${languange}`)
? ? ? /*路徑參數,需要使用params ?*/
? ? ? router.push({name:"showDetail",params:{id:id,language:language}})
? }
? let showDetail2= (id,language)=>{
? ? ? /*uri鍵值對參數,需要使用query */
? ? ? router.push({path:"/showDetail2",query:{id:id,language:language}})
? }
</script>
<template>
? ? <div>
? ? ? <h1>App頁面</h1>
? ? ? <hr/>
? ? ? <!-- 路徑參數 ? -->
? ? ? <router-link to="/showDetail/1/JAVA">showDetail路徑傳參顯示JAVA</router-link>
? ? ? <button @click="showDetail(1,'JAVA')">showDetail動態路由路徑傳參顯示JAVA</button>
? ? ? <hr/>
? ? ? <!-- 鍵值對參數 -->
? ? ? <router-link v-bind:to="{path:'/showDetail2',query:{id:1,language:'Java'}}">showDetail2鍵值對傳參顯示JAVA</router-link>
? ? ? <button @click="showDetail2(1,'JAVA')">showDetail2動態路由鍵值對傳參顯示JAVA</button>
? ? ? <hr>
? ? ? showDetail視圖展示:<router-view name="showDetailView"></router-view>
? ? ? <hr>
? ? ? showDetail2視圖展示:<router-view name="showDetailView2"></router-view>
? ? </div>
</template>
<style scoped>
</style>
```
+ 修改router.js增加路徑參數占位符
``` javascript
// 導入路由創建的相關方法
import {createRouter,createWebHashHistory} from 'vue-router'
// 導入vue組件
import ShowDetail from '../components/ShowDetail.vue'
import ShowDetail2 from '../components/ShowDetail2.vue'
// 創建路由對象,聲明路由規則
const router = createRouter({
? ? history: createWebHashHistory(),
? ? routes:[
? ? ? ?
? ? ? ? {
? ? ? ? ? ? /* 此處:id ?:language作為路徑的占位符 */
? ? ? ? ? ? path:'/showDetail/:id/:language',
? ? ? ? ? ? /* 動態路由傳參時,根據該名字找到該路由 */
? ? ? ? ? ? name:'showDetail',
? ? ? ? ? ? components:{
? ? ? ? ? ? ? ? showDetailView:ShowDetail
? ? ? ? ? ? } ?
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? path:'/showDetail2',
? ? ? ? ? ? components:{
? ? ? ? ? ? ? ? showDetailView2:ShowDetail2
? ? ? ? ? ? } ?
? ? ? ? },
? ? ]
})
// 對外暴露路由對象
export default router;
?
?
?
+ ShowDetail.vue 通過useRoute獲取路徑參數
``` html
<script setup type="module">
? ? import{useRoute} from 'vue-router'
? ? import { onUpdated,ref } from 'vue';
? ? // 獲取當前的route對象
? ? let route =useRoute()
? ? let languageId = ref(0)
? ? let languageName = ref('')
? ? // ?借助更新時生命周期,將數據更新進入響應式對象
? ? onUpdated (()=>{
? ? ? ? // 獲取對象中的參數
? ? ? ? languageId.value=route.params.id
? ? ? ? languageName.value=route.params.language
? ? ? ? console.log(languageId.value)
? ? ? ? console.log(languageName.value)
? ? })
? ?
</script>
<template>
? ? <div>
? ? ? ? <h1>ShowDetail頁面</h1>
? ? ? ? <h3>編號{{route.params.id}}:{{route.params.language}}是世界上最好的語言</h3>
? ? ? ? <h3>編號{{languageId}}:{{languageName}}是世界上最好的語言</h3>
? ? </div>
</template>
<style scoped>
</style>
```
- ? ShowDetail2.vue通過useRoute獲取鍵值對參數
```html
<script setup type="module">
? ? import{useRoute} from 'vue-router'
? ? import { onUpdated,ref } from 'vue';
? ? // 獲取當前的route對象
? ? let route =useRoute()
? ? let languageId = ref(0)
? ? let languageName = ref('')
? ? // ?借助更新時生命周期,將數據更新進入響應式對象
? ? onUpdated (()=>{
? ? ? ? // 獲取對象中的參數(通過query獲取參數,此時參數是key-value形式的)
? ? ? ? console.log(route.query)
? ? ? ? console.log(languageId.value)
? ? ? ? console.log(languageName.value)
? ? ? ? languageId.value=route.query.id
? ? ? ? languageName.value=route.query.language
? ? ? ?
? ? })
? ?
</script>
<template>
? ? <div>
? ? ? ? <h1>ShowDetail2頁面</h1>
? ? ? ? <h3>編號{{route.query.id}}:{{route.query.language}}是世界上最好的語言</h3>
? ? ? ? <h3>編號{{languageId}}:{{languageName}}是世界上最好的語言</h3>
? ? </div>
</template>
<style scoped>
</style>
五、路由守衛
在 Vue 3 中,路由守衛是用于在路由切換期間進行一些特定任務的回調函數。路由守衛可以用于許多任務,例如驗證用戶是否已登錄、在路由切換前提供確認提示、請求數據等。Vue 3 為路由守衛提供了全面的支持,并提供了以下幾種類型的路由守衛:
1. ?全局前置守衛:在路由切換前被調用,可以用于驗證用戶是否已登錄、中斷導航、請求數據等。
2. ?全局后置守衛:在路由切換之后被調用,可以用于處理數據、操作 DOM 、記錄日志等。
3. ?守衛代碼的位置: 在router.js中
//全局前置路由守衛
router.beforeEach( (to,from,next) => {
? ? //to 是目標地包裝對象 ?.path屬性可以獲取地址
? ? //from 是來源地包裝對象 .path屬性可以獲取地址
? ? ??next是方法,不調用默認攔截! next() 放行,直接到達目標組件
? ? next('/地址')可以轉發到其他地址,到達目標組件前會再次經過前置路由守衛
? ? console.log(to.path,from.path,next)
? ? //需要判斷,注意避免無限重定向,所以一般需要寫在分支條件下。
? ? if(to.path == '/index'){
? ? ? ? next()
? ? }else{
? ? ? ? next('/index')
? ? }
? ?
} )
//全局后置路由守衛
router.afterEach((to, from) => {
? ? console.log(`Navigate from ${from.path} to ${to.path}`);
});
> 登錄案例,登錄以后才可以進入home,否則必須進入login
+ 定義Login.vue
```html
<script setup>
? ? import {ref} from 'vue'
? ? import {useRouter} from 'vue-router'
? ? let username =ref('')
? ? let password =ref('')
? ? let router = useRouter();
? ? let login = () =>{
? ? ? ? console.log(username.value,password.value)
? ? ? ? if(username.value == 'root' & password.value == '123456'){
? ? ? ? ? ? router.push({path:'/home',query:{'username':username.value}})
? ? ? ? ? ? //登錄成功利用前端存儲機制,存儲賬號!
? ? ? ? ? ? localStorage.setItem('username',username.value)
? ? ? ? ? ? //sessionStorage.setItem('username',username)
? ? ? ? }else{
? ? ? ? ? ? alert('登錄失敗,賬號或者密碼錯誤!');
? ? ? ? }
? ? }
</script>
<template>
? ?
? ? <div>
? ? ? ? 賬號: <input type="text" v-model="username" placeholder="請輸入賬號!"><br>
? ? ? ? 密碼: <input type="password" v-model="password" placeholder="請輸入密碼!"><br>
? ? ? ? <button @click="login()">登錄</button>
? ? </div>
</template>
<style scoped>
</style>
```
+ 定義Home.vue
```html
<script setup>
?import {ref} from 'vue'
?import {useRoute,useRouter} from 'vue-router'
?let route =useRoute()
?let router = useRouter()
?// ?并不是每次進入home頁時,都有用戶名參數傳入
?//let username = route.query.username
?let username =window.localStorage.getItem('username');
?let logout= ()=>{
? ? // 清除localStorge中的username
? ? //window.sessionStorage.removeItem('username')
? ? window.localStorage.removeItem('username')
? ? // 動態路由到登錄頁
? ? router.push("/login")
?}
</script>
<template>
? ? <div>
? ? ? ? <h1>Home頁面</h1>
? ? ? ? <h3>歡迎{{username}}登錄</h3>
? ? ? ? <button @click="logout">退出登錄</button>
? ? </div>
</template>
<style scoped>
</style>
```
+ App.vue
```html
<script setup type="module">
?
</script>
<template>
? ? <div>
? ? ?
? ? ? <router-view></router-view>
? ? ?
? ? </div>
</template>
<style scoped>
</style>
```
+ 定義routers.js
``` javascript
// 導入路由創建的相關方法
import {createRouter,createWebHashHistory} from 'vue-router'
// 導入vue組件
import Home from '../components/Home.vue'
import Login from '../components/login.vue'
// 創建路由對象,聲明路由規則
const router = createRouter({
? ? history: createWebHashHistory(),
? ? routes:[
? ? ? ? {
? ? ? ? ? ? path:'/home',
? ? ? ? ? ? component:Home
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? path:'/',
? ? ? ? ? ? redirect:"/home"
? ? ? ? },
? ? ? ? {
? ? ? ? ? ? path:'/login',
? ? ? ? ? ? component:Login
? ? ? ? },
? ? ]
})
// 設置路由的全局前置守衛
router.beforeEach((to,from,next)=>{
? ? /*
? ? to 要去那
? ? from 從哪里來
? ? next 放行路由時需要調用的方法,不調用則不放行
? ? */
? ? console.log(`從哪里來:${from.path},到哪里去:${to.path}`)
? ? if(to.path == '/login'){
? ? ? ? //放行路由 ?注意放行不要形成循環 ?
? ? ? ? next()
? ? }else{
? ? ? ? //let username =window.sessionStorage.getItem('username');
? ? ? ? let username =window.localStorage.getItem('username');
? ? ? ? if(null != username){
? ? ? ? ? ? next()
? ? ? ? }else{
? ? ? ? ? ? next('/login')
? ? ? ? }
? ? }
})
// 設置路由的全局后置守衛
router.afterEach((to,from)=>{
? ? console.log(`從哪里來:${from.path},到哪里去:${to.path}`)
})
// 對外暴露路由對象
export default router;
```
+ 啟動測試
```shell
npm run dev