$route 与 $router
每个注册过的路由都有自己的 $route 属性,里面包含query参数、params参数、meta元信息等属性。
所有路由共用一个 $router,就像一个路由器管理所有的路由接口。
$router 包括一些路由信息,比如:当前所在的路由 this.$router.currentRoute,已配置好的路由 this.$router.options.routes。
$router 提供了一些方法,比如 push跳转页面 addRoute增加路由。
路由的query传参
query传参类似于get请求,将参数信息携带在url中,可以通过 this.$route.query 获取。
<!-- 跳转路由并携带query参数,固定参数 -->
<router-link to="/login?user=admin" >登录</router-link>
<!-- 跳转路由并携带query参数,动态参数 -->
<router-link :to="`/login?user=${user}`" >登录</router-link>
<!-- 跳转路由并携带query参数,对象写法 -->
<!-- 使用query传参,通过path或name跳转都可 -->
<router-link :to="{
path:'/login',
// name:'login',
query:{
user:user
}
}" >登录</router-link>
data(){
return {
user:'admin'
}
}
路由的params传参
通过params传递的参数可以通过 this.$route.params 获取。
<!-- 跳转路由并携带params参数,固定参数 -->
<router-link to="/login/admin" >登录</router-link>
<!-- 跳转路由并携带params参数,动态参数 -->
<router-link :to="`/login/${user}`" >登录</router-link>
<!-- 跳转路由并携带params参数,对象写法 -->
<!-- 使用params传参,只能通过name跳转 -->
<router-link :to="{
name:'login',
params:{
user:user
}
}" >登录</router-link>
data(){
return {
user:'admin'
}
}
使用params传参,在配置路由时需要在path路径后加上‘/:user’,声明接收params参数,可传递多个参数。
const routes = [
{
path:'/login/:user', // 使用占位符声明接收params参数
name:'login',
component:()=>import('../views/LoginView.vue')
}
]
当没有设置动态路由时,如果通过字符串路径跳转并使用params传参,浏览器会找不到对应的页面,如果通过一个描述地址的对象路径跳转并使用params传参,只能在第一次进入页面时可以通过 this.$route.params 获取参数,刷新后将无法获取,此时可以在第一次进入页面时使用本地缓存。
created(){
if(this.$route.params.id){
localStorage.id = this.$route.params.id
}
let id = this.$route.params.id || localStorage.id
console.log(id);
}
路由Props配置
当传递多个参数时,可以通过 props 配置统一接收。
const routes = [
{
path:'/login/:user/:id', // 使用占位符声明接收params参数
name:'login',
component:()=>import('../views/LoginView.vue'),
// props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给LoginView组件
// 对象写法使用较少,因为传递的是固定的数据
// props:{user:'admin',id:001}
// props的第二种写法,值为布尔值
// 若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给LoginView组件
// props:true
// props的第三种写法,值为函数,可以接收$route参数
props($route){
return {user:$route.query.user,id:$route.query.id}
}
// 连续解构赋值写法,缺点是语义化不明确
// props({query:{user,id}}){
// return {user,id}
// }
}
]
LoginView 组件通过props接收。
export default {
name:'LoginView',
props:['user','id']
}
手动添加路由与子路由
this.$route 提供了 addRoute 方法可以添加路由或给路由添加子路由。
export default {
name:'LoginView',
methods:{
// 添加一级路由vip
addR(){
this.$router.addRoute({
path: '/vip',
name: 'vip',
/* 路径使用@表示src的方式实现 */
/* 或者在本页面 使用./views/VipView.vue 的方式 获取页面*/
component: () => import('@/views/VipView.vue')
})
console.log(this.$router)
},
/* 给about加上子路由 */
addR2(){
/* 添加子路由的时候需要第一个参数是主路由的name值 */
this.$router.addRoute('about',{
path:'aboutchild2',
name:'aboutchild2',
component: () => import('@/views/AboutChild2.vue'),
})
/* this.$router.currentRout表示当前所在的路由 */
console.log(this.$router.currentRoute)
}
}
}
编程式路由导航(跳转和解决报错)
this.$route 提供了 push 、 replace 、go 、back、forward 五种跳转路由的方法。
push 方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。
replace 方法在导航时不会向 history 添加新记录,它会替换当前的 URL。
push 方法和replace 方法参数可以是一个字符串路径,或者一个描述地址的对象。
go 方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于 window.history.go(n)。
export default {
name:'LoginView',
methods:{
tiaozhuan(){
// push跳转会增加浏览历史记录,可以通过浏览器的后退按钮返回上一个网页
// this.$router.push('/about')
// this.$router.push({name:'about'})
// replace跳转会替换当前网页的浏览历史记录,不能通过浏览器的后退按钮返回上一个网页
// 在 routeLink 标签中添加replace指令就可以使用replace跳转模式
// this.$router.replace('/about')
// go跳转采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于window.history.go(n)。
// 返回上一页后退()
// this.$router.back();
// this.$router.go(-1)
// 刷新
// this.$router.go(0)
// 去下一页(前进)
// this.$router.forward();
// this.$router.go(1)
}
}
}
this.$router 提供的跳转方法只能跳转一次,跳转多次会报错,解决方法:在配置路由的 index.js 中添加如下代码。
const VueRouterPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (to) {
return VueRouterPush.call(this, to).catch(err => err)
}
设置路由钩子
| 守卫 | 可接收参数 | 触发时间 |
|---|---|---|
| 全局前置守卫beforeEach | to,from,next | 当一个导航触发时,全局前置守卫按照创建顺序调用 |
| 全局后置守卫afterEach | to,from | 导航被确认后 |
| 路由独享守卫beforEnter | to,from,next | 只在进入路由时触发 |
| 组件内进入路由守卫beforeRouteEnter | to,from,next | 在渲染该组件的对应路由被验证前调用,不能获取组件实例 this,可以通过传一个回调(vm形参)给 next 来访问组件实例 |
| 组件内路由更新守卫beforeRouteUpdate | to,from,next | 在当前路由改变,但是该组件被复用时调用,举例来说,对于一个带有动态参数的路径 /users/:id,在 /users/1 和 /users/2 之间跳转的时候;可以获取组件实例 this |
| 组件内离开路由守卫beforeRouteLeave | to,from,next | 在导航离开渲染该组件的对应路由时调用,可以获取组件实例 this |
路由元信息
我们在配置路由时,可以通过接收属性对象的 meta 属性来附加任意信息到路由上,如过渡名称、谁可以访问路由等,它可以在路由地址和导航守卫上都被访问到。
const routes = [
{
path: '/posts',
component: PostsLayout,
children: [
{
path: 'new',
component: PostsNew,
// 只有经过身份验证的用户才能创建帖子
meta: { requiresAuth: true }
},
{
path: ':id',
component: PostsDetail
// 任何人都可以阅读文章
meta: { requiresAuth: false }
}
]
}
]
缓存路由组件
当路由路径发生变化时,旧的路由路径对应的路由组件会被销毁,新的路由路径对应的路由组件会被创建,与此同时,旧的路由路径对应的路由组件中的一些表单元素信息就会丢失,我们可以通过缓存路由组件来暂时保存这些信息。
<!-- 使用<keep-alive></keep-alive>标签包裹组件展示区域 -->
<!-- keep-alive标签内没有includes属性时,在展示区域内展示的所有组件都将被缓存 -->
<!-- 想缓存的组件只有一个时,includes属性值直接写组件名即可 -->
<!-- 组件名是组件的script导出的name,不是路由的name -->
<!-- 想缓存的组件有有个时,includes属性值动态绑定一个数组,数组的每一项为想缓存的组件名 -->
<keep-alive includes="news">
<router-view/>
</keep-alive>
<keep-alive :includes="['news','message']">
<router-view/>
</keep-alive>
由于被缓存的组件不会被摧毁,若组件内存在定时器,定时器也不会被停止,一直运行消耗性能,这时可以将定时器写在activated激活生命钩子内,将消除定时器写在deactivated失活生命钩子内。
activated激活生命钩子和deactivated失活生命钩子是路由组件独有的生命周期钩子。
activated(){
this.timer = setInterval(() => {
console.log('@');
}, 500);
},
deactivated(){
clearInterval(this.timer)
}
关于路由更多详情请见Vue Router官方文档。