学习呦
14 10月 2025 18 min read

路由

Written by 米豆

路由匹配

路由会按照 path配置的 URL 进行匹配,如果有 params参数,则匹配的URL 会按照 params匹配规则匹配参数

const routes = [
// 匹配 /o/3549
{ path: '/o/:orderId' },
// 匹配 /p/books
{ path: '/p/:productName' },

// /:orderId -> 仅匹配数字
{ path: '/:orderId(\\d+)' },

// /:chapters -> 匹配 1 个或者多个 /one, /one/two
{ path: '/:chapters+' },
// /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等 匹配 0 个或者多个
{ path: '/:chapters*' },


// 匹配 /users 和 /users/posva
{ path: '/users/:userId?' },
]

上面的例子,展示了可以写正则表达式,可以写匹配数量,可以写可选参数

组件

  • 路由切换 router-link
  • 路由展示 router-view

PS. 一般将路由使用的组件放入项目中的pages文件夹下 每个路由组件中有两个属性

  • route
  • router

route是这个组件自己的路由配置,router是整个路由器,整个vue组件仅仅有一个router

route-view

<!-- 指定组件的呈现位置 -->
<router-view></router-view>

<!-- route-view 插槽-->
<router-view v-slot="{ Component }">
<component :is="Component" />
</router-view>

命名视图

可以在一个组件中写多个 <RouteView>,比如页面中有多个小的组件,每一个组件都是一个路由组件,这时如果只有一个 <RouteView>就只能显示一个组件,所以得用到命名视图

<router-view class="view left-sidebar" name="LeftSidebar" />
<router-view class="view main-content" />
<router-view class="view right-sidebar" name="RightSidebar" />

那么命名视图的路由配置怎么写呢?

import LeftSidebar from 'LeftSidebar.vue'
import RightSidebar from 'RightSidebar.vue'
import Home from 'Home.vue'

routes: [
{
path: '/',
components: {
default: Home,
// LeftSidebar: LeftSidebar 的缩写
LeftSidebar,
// 它们与 `<router-view>` 上的 `name` 属性匹配
RightSidebar,
},
},
]

replace属性:路由的两种模式之一replace模式,会替换路由,而不是push路由

<router-link replace .......>News</router-link>
<router-link class="list-group-item" active-class="active" to="/home/news">
News
</router-link>

两个特有的生命周期函数

这两个生命周期其实是和<KeepAlive>组件有关的,也多少和路由有点联系

  • activated:路由组件被激活,相当于初始化挂载组件时会调用

  • deactivated:路由组件失活,也就是从路由缓存(或者就是缓存)中去除

如果设置了路由缓存,组件的销毁的生命周期就不会被调用了。但是可以通过上面的生命周期钩子来实现相同的逻辑,上面的生命周期会在组件渲染到页面(activated)和从页面消失(deactivated)的时候调用

路由配置

嵌套路由

路由配置:children配置项

{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News,
}
]
}

路由传参

三种方式

  • query 传参
  • param 传参
  • meta 传参

query参数

<!-- 跳转路由并携带query参数,to的字符串写法 -->
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
{{m.title}}
</router-link>

<!-- 跳转路由并携带query参数,to的对象写法 -->
<router-link :to="{
path:'/home/message/detail',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>

接收参数: this.$route.query.id、this.$route.query.title to可以简写,或者使用上面的对象形式

params参数

{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News
},
{
component:Message,
children:[
{
name:'xiangqing',
path:'detail/:id/:title', //使用占位符声明接收params参数
component:Detail,
props: true
}
]
}
]
}

注意⚠️,可以配置 props属性在 parmas路由传参的配置中,如果设置 props: true则表示把 parmas参数作为组件的 props 传入

<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="/home/message/detail/666/你好">跳转</router-link>

<!-- 跳转并携带params参数,to的对象写法 -->
<router-link
:to="{
name:'xiangqing',
params:{
id:666,
title:'你好'
}
}"
>跳转</router-link>

特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

params 传参的方式不能传递对象,只能传递字符串

meta路由元信息

在路由配置中的 meta选项中配置,可以配置对象,元信息会发送给路由组件

const routes = [
{
path: '/posts',
component: PostsLayout,
children: [
{
path: ':id',
component: PostsDetail,
// 任何人都可以阅读文章
meta: {
requiresAuth: false,
checkList: {
name: 'foo'
}
},
},
],
},
]

props配置

给路由组件传递一些props

  • 对象模式:将配置的props对象原样给路由组件

  • 布尔模式:将params参数传递给路由组件(这个只能 params 传参的时候使用)

  • 函数模式:可以将参数转换为其他类型

{
name:'xiangqing',
path:'detail/:id',
component:Detail,

//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
props:{a:900}

//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
props:true

//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props(route){
return {
id: route.query.id,
title: route.query.title
}
}
}

编程式路由

$router

push:this.$router.push({}) // 直接可以接受一个to属性中写好的配置对象

replace:this.$router.replace({}) // 同理

后退:this.$router.back()

前进:this.$router.forword()

路由缓存

准确来说应该是组件缓存,这个应该是 vue 的内部组件
<keep-alive></keep-alive>

路由守卫

路由跳转过程中执行的一些钩子,控制路由跳转权限

全局守卫

全局前置守卫

router.beforeEach(to, from, next)

概念:在跳转前执行的一个钩子,接收一个回调函数。其中有三个参数,to去哪的路由配置,from从哪来的路由配置,next可以执行跳转的函数

{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{isAuth:true,title:'新闻'}
},
]}
//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
next() //放行
}else{
alert('暂无权限查看')
next({name:'guanyu'})
}
}else{
next() //放行
}
})

全局后置路由守卫

router.afterEach(to,from)

概念:跳转执行后,会执行的钩子。初始化的时候也会调用

独享路由守卫

某一个路由独享的守卫,其他路由不会在此守卫生效

beforeEnter

组件内的守卫

  1. beforeRouteEnter()
  2. beforeRouteLeave()
  3. beforeRouteUpdate()

组件级别的守卫,在通过路由规则 进入/离开 对应的组件时会执行

注意⚠️:不是全局前置守卫和全局后置路由守卫

beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},

beforeRouteUpdate(){
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
}

beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},

composition API中使用路由

useRoute和useRouter

route 是组件的路由配置,每一个组件都有一个。router 是路由器,相当于 vue-route 的实例化,全局只有一个
在 <template>中可以使用 $route、$router来访问路由配置以及路由器,是不需要使用 import引入的

<script setup>
import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'

const route = useRoute()
const userData = ref()

// 当参数更改时获取用户信息
watch(
() => route.params.id,
async newId => {
userData.value = await fetchUser(newId)
}
)
</script>
↑