一、什么是导航守卫
当涉及到Vue路由时,导航守卫是一项非常有用的功能。导航守卫允许你在路由导航过程中执行一些操作,例如验证用户权限、重定向或取消导航等,导航守卫主要分为三种:全局导航守卫、独享导航守卫、组件内导航守卫。
二、全局导航守卫
全局导航守卫有三种:beforeEach(全局前置守卫)、beforeResolve(全局解析守卫)、afterEach(全局后置守卫)。
1.全局前置守卫
我们可以使用router.beforeEach注册一个全局前置守卫,beforeEach在路由切换之前调用,可以用来进行权限验证、登录状态检查等操作。
用户如果没有登录,只能访问登录界面,不能访问其他页面。用户如果登录了,就可以访问其他页面,不能访问登录页面。
js
router.beforeEach((to, from, next) => {
let token = userStore.token;
// 如果用户已登录
if(token) {
// 访问登录页则跳回首页
if(to.path == "/login"){
next({path: "/"});
} else {
// 如果访问其他页面则放行
next();
}
} else { // 如果用户未登录
if(to.path == "/login"){
next();
} else {
// 如果访问其他页面则返回登录界面
next({path: "/login"});
}
}
})
三个参数的含义:
to
: 表示即将要进入的目标路由。它是一个包含路由信息的对象,包括path、params、query等参数信息。我们可以通过to.path获取目标路由的路径,通过to.params获取目标路由的参数,通过to.query获取目标路由的查询参数等。from
: 表示当前导航正要离开的路由。它也是一个包含路由信息的对象,我们可以通过from.path获取当前路由的路径,通过from.params获取当前路由的参数,通过from.query获取当前路由的查询参数等。next
: 可选的第三个参数,是一个函数(放行函数),用于控制导航的行为。
这里列举一些next的具体用法:
next()
:调用next()表示继续导航,即允许用户访问目标路由。next(false)
:调用next(false)表示终止导航,即不允许用户访问目标路由。这通常用于进行权限验证或者登录状态检查,如果条件不满足,则终止导航。next('/path')
:调用next('/path')表示重定向导航到指定的路径。这可以用于在导航守卫中进行重定向,例如在未登录时将用户重定向到登录页面。next({ path: '/path' })
:调用next({ path: '/path' })表示重定向导航到指定的路径。与上一个用法相似,但使用了一个包含路径的对象作为参数。next(error)
:调用next(error)表示终止导航并传递一个错误对象。这可以用于在导航守卫中处理错误情况,例如在网络请求失败时中止导航并显示错误信息。next(callback)
:调用next(callback)表示异步导航,其中callback是一个回调函数。这可以用于在导航守卫中执行异步操作,例如在获取数据后再继续导航。
请注意,next方法只能在导航守卫函数中调用,并且每个导航守卫函数只能调用一次next方法,只能调用一次。
2.全局解析守卫
我们可以用router.beforeResolve注册一个全局守卫。beforeResolve在路由切换之前调用,但在beforeEach守卫之后调用。在该守卫中,可以在导航被确认之前执行异步操作或者获取组件数据,可以在所有组件内守卫和异步路由组件被解析之后调用。
js
router.beforeResolve((to, from, next) => {
// 在这里执行一些操作,例如加载数据
fetchData().then(() => {
next();
});
});
Vue-router的官网写道:router.beforeResolve是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。
3.全局后置守卫
我们可以使用router.afterEach方法注册一个全局后置钩子,afterEach在路由切换之后调用,可以用来进行页面统计、错误处理等操作,通常用于页面渲染完成后的操作。该守卫没有next参数,因此不能中止导航。
js
router.afterEach((to, from) => {
// 在这里执行一些操作,例如记录页面浏览历史
trackPageView(to.path);
});
比如说我们就可以利用前置守卫和后置守卫制作一个进度条,当然我们还需要引入第三方库及其样式,这样项目上方会出现进度条。
js
import nprogress from "nprogress";
import "nprogress/nprogress.css";
import router from "./router";
router.beforeEach((to, from, next) => {
nprogress.start();
next();
})
router.afterEach((to, from) => {
nprogress.done();
})
三、独享导航守卫
除了全局导航守卫外,我们还可以在路由配置中为特定的路由定义独享的守卫。路由独享守卫仅对特定的路由生效,可以用于处理特定路由的逻辑。beforeEnter守卫只在进入路由时触发,不会在params、query或hash改变时触发。
例如,从/users/2进入到/users/3或者从/users/2#info进入到/users/2#projects时,守卫不会触发,只有在从一个不同的路由导航时,才会被触发。
js
const routes = [
{
path: '/home',
component: Home,
beforeEnter: (to, from, next) => {
// 在进入路由之前执行一些操作
if (isLoggedIn()) {
// 用户已登录,允许访问路由
next();
} else {
// 用户未登录,重定向到登录页面
next('/login');
}
}
},
// 其他路由配置...
]
通过使用独享导航守卫,我们可以在路由级别上对访问权限进行一定的控制。
四、组件内导航守卫
除了全局导航守卫和路由独享守卫外,我们还可以在路由组件内直接定义路由导航守卫。这些守卫将在组件的生命周期钩子中被调用,用于在组件内部控制路由导航行为。
- beforeRouteEnter:用于在路由进入组件之前执行操作,无法通过this访问组件实例,因为当守卫执行时,组件实例还没被创建。
- beforeRouteUpdate:用于在组件复用时,路由参数发生变化时执行操作,可以通过this访问组件实例,因为组件已经挂载好了。
- beforeRouteLeave:用于在路由离开组件之前执行操作,可以通过this访问组件实例。
js
const UserDetails = {
template: `...`,
beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},
}
在beforeRouteEnter守卫中,可以通过传递一个回调函数给next方法来访问组件实例。这个回调函数会在路由确认之后被调用,此时组件实例已经被创建。回调函数的参数就是组件实例,因此可以通过这个参数访问组件实例的方法和属性。
js
export default {
beforeRouteEnter(to, from, next) {
next(vm => {
// 在进入组件之后执行一些操作
// 可以访问组件实例的this上下文
vm.doSomething();
});
},
beforeRouteUpdate(to, from, next) {
// 在这里执行一些操作,例如重新加载数据
fetchData().then(() => {
next();
});
},
beforeRouteLeave(to, from, next) {
// 在这里执行一些操作,例如提示用户保存未保存的数据
if (hasUnsavedChanges) {
if (confirm('你有未保存的数据,确定要离开吗?')) {
next();
} else {
next(false);
}
} else {
next();
}
},
};
五、最后的话
Vue导航守卫是Vue Router提供的一种机制,用于在路由导航过程中执行一些操作。全局守卫可以在整个应用程序的路由导航过程中被调用,而路由独享守卫只对特定的路由生效。通过使用导航守卫,我们可以实现权限验证、数据预加载等功能,提升用户体验和应用程序的安全性。
能力一般,水平有限,本文可能存在纰漏或错误,如有问题欢迎指正,感谢你阅读这篇文章,如果你觉得写得还行的话,不要忘记点赞、评论、收藏哦!祝生活愉快!