3.3 动态路由匹配
嵌套路由的实现Vue2与Vue3相同。
动态路由指的是:
把 Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。
在 vue-router 中使用英文的冒号(:
)来定义路由的参数项。
3.3.1 动态路由的使用
路由连接的声明如下:
<router-link to="/movie/1">洛基</router-link> <router-link to="/movie/2">雷神</router-link> <router-link to="/movie/3">复联</router-link>
要实现将如下的三行合并成一行,提高路由的复用性:
{ path: '/movie/1', component: Movie }, { path: '/movie/2', component: Movie }, { path: '/movie/3', component: Movie }
路由中的动态参数使用 :
进行声明,冒号后面是动态参数的名称。
合并代码如下:
{ path: '/movie/:id', component: Movie },
可以在对应组件中根据动态传入的参数 id 值来动态渲染组件。
如何获取动态传入的参数,如下:
3.3.2 $route.params 参数对象
在动态路由渲染出来的组件中,可以使用this.$route.params
对象访问到动态匹配的参数值。
所以可以在路由渲染出来的组件中使用this.$route.params
获取动态匹配的参数值。
<template> <div class="movie-container"> <!-- this.$route 是路由的“参数对象” --> <!-- this.$router 是路由的“导航对象” --> <h3>Movie 组件 --- {{ $route.params.mid }}</h3> <button @click="showThis">打印 this</button> </div> </template> <script> export default { name: 'Movie', methods: { showThis() { console.log(this) } } } </script> <style lang="less" scoped> .movie-container { min-height: 200px; background-color: lightsalmon; padding: 15px; } </style>
3.3.3 使用 props 接收路由参数
为了简化路由参数的获取形式,vue-router 允许在路由规则中开启 props 传参。
Movie.vue
<template> <div class="movie-container"> <!-- this.$route 是路由的“参数对象” --> <!-- this.$router 是路由的“导航对象” --> <h3>Movie 组件 --- {{ $route.params.mid }} --- {{ mid }}</h3> <button @click="showThis">打印 this</button> </div> </template> <script> export default { name: 'Movie', // 接收 props 数据 props: ['mid'], methods: { showThis() { console.log(this) } } } </script> <style lang="less" scoped> .movie-container { min-height: 200px; background-color: lightsalmon; padding: 15px; } </style>
路由规则:
// 创建路由的实例对象 const router = new VueRouter({ // routes 是一个数组,作用:定义 “hash 地址” 与 “组件” 之间的对应关系 routes: [ // 重定向的路由规则 { path: '/', redirect: '/home' }, // 路由规则 { path: '/home', component: Home }, // 需求:在 Movie 组件中,希望根据 id 的值,展示对应电影的详情信息 // 可以为路由规则开启 props 传参,从而方便的拿到动态参数的值 { path: '/movie/:mid', component: Movie, props: true }, { path: '/about', component: About, // redirect: '/about/tab1', children: [ // 子路由规则 // 默认子路由:如果 children 数组中,某个路由规则的 path 值为空字符串,则这条路由规则,叫做“默认子路由” { path: '', component: Tab1 }, { path: 'tab2', component: Tab2 } ] }, { path: '/login', component: Login }, { path: '/main', component: Main } ] })
App.vue
<template> <div class="app-container"> <h1>App 组件</h1> <router-link to="/home">首页</router-link> <router-link to="/movie/1">洛基</router-link> <router-link to="/movie/2">雷神</router-link> <router-link to="/movie/3">复联</router-link> <router-link to="/about">关于</router-link> <hr /> <!-- 只要在项目中安装和配置了 vue-router,就可以使用 router-view 这个组件了 --> <!-- 它的作用很单纯:占位符 --> <router-view></router-view> </div> </template> <script> export default { name: 'App' } </script> <style lang="less" scoped> .app-container { background-color: #efefef; overflow: hidden; margin: 10px; padding: 15px; > a { margin-right: 10px; } } </style>
3.3.4 route中的参数
注意1:
在 hash 地址中, / 后面的参数项,叫做“路径参数”
在路由“参数对象”中,需要使用 this.$route.params 来访问路径参数
注意2:
在 hash 地址中,? 后面的参数项,叫做“查询参数”
在路由“参数对象”中,需要使用 this.$route.query 来访问查询参数
<router-link to="/movie/2?name=zs&age=20">雷神</router-link>
注意3:
在 this.$route 中,path 只是路径部分;fullPath 是完整的地址
例如:
/movie/2?name=zs&age=20 是 fullPath 的值
/movie/2 是 path 的值
3.4 声明式导航 & 编程式导航
嵌套路由的实现Vue2与Vue3相同。
3.4.1 声明式导航
在浏览器中,点击链接实现导航的方式,叫做声明式导航。
例如:
普通网页中点击<a>
链接、vue 项目中点击 <router-link>
都属于声明式导航。
3.4.2 编程式导航
在浏览器中,调用 API 方法实现导航的方式,叫做编程式导航。
例如:
普通网页中调用 location.href 跳转到新页面的方式,属于编程式导航。
3.4.3 vue-router 中的编程式导航 API
vue-router 提供了许多编程式导航的 API,其中最常用的导航 API 分别是:
①
this.$router.push('hash 地址')
跳转到指定 hash 地址,并增加一条历史记录
② this.$router.replace('hash 地址')
跳转到指定的 hash 地址,并替换掉当前的历史记录
③ this.$router.go(数值 n)
实现导航历史前进、后退
3.4.4 $router.push与$router.replace
调用 this.$router.push()
方法或this.$router.replace()
方法,可以跳转到指定的 hash 地址,从而展示对应的组件页面。
push 和 replace 的区别:
push 会增加一条历史记录
replace 不会增加历史记录,而是替换掉当前的历史记录
<template> <div class="home-container"> <h3>Home 组件</h3> <hr /> <button @click="gotoLk">通过 push 跳转到“洛基”页面</button> <button @click="gotoLk2">通过 replace 跳转到“洛基”页面</button> </div> </template> <script> export default { name: 'Home', methods: { gotoLk() { // 通过编程式导航 API,导航跳转到指定的页面 this.$router.push('/movie/1') }, gotoLk2() { // 通过编程式导航 API,导航跳转到指定的页面 this.$router.replace('/movie/1') } } } </script> <style lang="less" scoped> .home-container { min-height: 200px; background-color: pink; padding: 15px; } </style>
3.4.5 $router.go
调用 this.$router.go()
方法,可以在浏览历史中前进和后退。
<template> <div class="movie-container"> <!-- this.$route 是路由的“参数对象” --> <!-- this.$router 是路由的“导航对象” --> <h3>Movie 组件 --- {{ $route.params.mid }} --- {{ mid }}</h3> <button @click="showThis">打印 this</button> <button @click="goback">后退</button> </div> </template> <script> export default { name: 'Movie', // 接收 props 数据 props: ['mid'], methods: { showThis() { console.log(this) }, goback() { // go(-1) 表示后退一层 // 如果后退的层数超过上限,则原地不动 this.$router.go(-1) } } } </script> <style lang="less" scoped> .movie-container { min-height: 200px; background-color: lightsalmon; padding: 15px; } </style>
3.4.6 $router.go 的简化用法
在实际开发中,一般只会前进和后退一层页面。因此 vue-router 提供了如下两个便捷方法:
① $router.back()
在历史记录中,后退到上一个页面
② $router.forward()
在历史记录中,前进到下一个页面
<template> <div class="movie-container"> <!-- this.$route 是路由的“参数对象” --> <!-- this.$router 是路由的“导航对象” --> <h3>Movie 组件 --- {{ $route.params.mid }} --- {{ mid }}</h3> <button @click="showThis">打印 this</button> <button @click="goback">后退</button> <!-- 在行内使用编程式导航跳转的时候,this 必须要省略,否则会报错! --> <button @click="$router.back()">back 后退</button> <button @click="$router.forward()">forward 前进</button> </div> </template> <script> export default { name: 'Movie', // 接收 props 数据 props: ['mid'], methods: { showThis() { console.log(this) }, goback() { // go(-1) 表示后退一层 // 如果后退的层数超过上限,则原地不动 this.$router.go(-1) } } } </script> <style lang="less" scoped> .movie-container { min-height: 200px; background-color: lightsalmon; padding: 15px; } </style>
3.5 导航守卫
Vue2与Vue3
导航守卫可以控制路由的访问权限。
3.5.1 全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫。
全局导航守卫会拦截每个路由规则,从而对每个路由进行访问权限的控制。
因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制。
可以按照如下的方式定义全局导航守卫:
// 创建路由的实例对象 const router = new VueRouter( {...} ) // 为 router 实例对象,声明全局前置导航守卫 // 只要发生了路由的跳转,必然会触发 beforeEach 指定的 function 回调函数 router.beforeEach( function() {} )
3.5.2 守卫方法的 3 个形参
// to 表示将要访问的路由的信息对象
// from 表示将要离开的路由的信息对象
// next() 函数表示放行的意思
// 为 router 实例对象,声明全局前置导航守卫 // 只要发生了路由的跳转,必然会触发 beforeEach 指定的 function 回调函数 router.beforeEach(function(to, from, next) { // to 表示将要访问的路由的信息对象 // from 表示将要离开的路由的信息对象 // next() 函数表示放行的意思 })
注意:
① 在守卫方法中如果不声明 next 形参,则默认允许用户访问每一个路由!
② 在守卫方法中如果声明了 next 形参,则必须调用 next() 函数,否则不允许用户访问任何一个路由!