前言
在实际的场景中,当用户访问的是一个页面,但可能出现了一些错误,需要给他呈现另一个页面。或者,当用户的注册状态已经过期,需要跳转到登录页,让用户登录后使用。这些场景下就需要用到路由重定向。别名可以理解为重定向的一种,只不过他的 url 是不改变的,也就是说,表面上的 url 不变,但实际上去的是其他页面。导航守卫可以结合登录来说,例如现在有一个后台管理系统,不登录、非管理人员不予呈现页面。在他访问站点时,先进行登录状态的判断,如果没有登录,则重定向到登录页,其他的页面坚决不可以呈现。这就是导航守卫。
重定向
重定向的实现很简单,只需要在路由表中使用 redirect
属性就好:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
redirect
后面可以跟路径,也可以跟路由名,甚至可以跟一个函数,函数返回一个路径。但一般直接使用路径,毕竟功能一样的情况下,肯定选择写得最少的那个。
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
const router = new VueRouter({
routes: [
{ path: '/a', redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
})
路由别名
官网描述:/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
尽管表面访问的是 /a
,但实际上呈现的页面是/b
,不过在路径显示上依然显示/a
。别名使用属性 alias 实现。
const router = new VueRouter({
routes: [
{ path: '/a', component: A, alias: '/b' }
]
})
导航守卫
Vue导航守卫这一章节的文档一开头就给我们说:参数的改变并不会触发导航守卫,要想监听路由的变化并做出相应的操作,就必须使用 watch
方法或者beforeRouteUpdate()
。
// watch 方法
watch: {
// 通过监听路由变化进行数据的更替
$route(to) {
if (to.path === '/all') {
this.filterdTaskList = this.taskList
} else if (to.path === '/active') {
this.filterdTaskList = this.taskList.filter(ele => ele.chosen === false)
} else if (to.path === '/completed') {
this.filterdTaskList = this.taskList.filter(ele => ele.chosen === true)
}
}
},
// beforeRouteUpdate 方法,其中的代码并不重要,理解怎么用就好
beforeRouteUpdate (to, from, next) {
if (to.path === '/all') {
this.filterdTaskList = this.taskList
next()
} else if (to.path === '/active') {
this.filterdTaskList = this.taskList.filter(ele => ele.chosen === false)
next()
} else if (to.path === '/completed') {
this.filterdTaskList = this.taskList.filter(ele => ele.chosen === true)
next()
}
},
全局导航守卫
不过这并不是今天的主题。回到导航守卫,我们前面讲过一点导航守卫的作用:导航守卫在于保护页面,没有权限的用户或者被限制部分权限的用户在访问网站或者某些页面时是不被允许的。一般情况下,大家面临最多的情况是用户未登录或登录过期时需要调用全局导航守卫,直接跳转到登录页面,引导用户进行登录:
// 以下代码写在 router 文件夹下的 index.js 文件中,与路由表 routes 同级
// to,要去的路径;from,来时的路径,一般用不到;next,函数,
// 不调用的话这个守卫钩子不会进行下一步
router.beforeEach((to, from, next) => {
// 判断路径是否是登录页
if (to.path === '/login') {
// 是登录页,执行下一步
next();
} else {
// 不是登录页,判断本地有无 token
let token = localStorage.getItem('Authorization');
if (token === null || token === ' ') {
// token 为空或不存在,跳转到登录页
next('/login');
} else {
next();
}
}
})
可能还是有人不太懂,对此体会不深,觉得比较飘渺,貌似自己没遇到过。那可以想象以下场景,你在某个人那里得到一个网站的链接,但是这个链接的路径不是网站的首页,而是那个人登录后访问了页面复制给你的链接,这时你打开这个链接,网站检测到你没有登录,便会跳转到登录页。可以拿一个视频网站来试试。
局部导航守卫
既然有全局导航守卫,就会有相应的局部导航守卫。所谓局部,也就是指组件内的导航守卫了。这里的守卫主要是用于监测路由导航到该组件的进程,并在进程中做一些操作,类似于生命周期钩子函数:
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
可以看到 beforeRouteUpdate 这个方法,我们在本节开头讲过。三个守卫分别对应导航前、导航中、导航后。beforeRouteUpdate
的用法正如前面演示的那样,用于组件内监测路由变化,并做出相应操作。beforeRouteLeave
则可以用于禁止用户在还未保存修改前突然离开。
beforeRouteLeave (to, from, next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
// 如果用户确认离开,则离开
if (answer) {
next()
} else {
// 否则取消离开
next(false)
}
}
其他的导航守卫这里便不在做演示了,在平时开发中这几个守卫比较常用,有需要有兴趣的同学可以去官网或视频网站找找相关教学。