网站
引入
在 Vue 项目中,用户访问不同页面时,通常需要根据当前登录状态判断是否允许进入某个路由。例如,未登录用户可以访问登录页,但不能直接访问用户中心或管理后台。
如果每个页面都单独判断登录状态,代码容易重复。Vue Router 提供了路由守卫,可以在路由跳转前统一执行检查逻辑。
正文
定义
全局前置守卫
router.beforeEach()会在每一次路由跳转发生之前执行。它可以检查登录状态、权限和路由信息,然后决定本次跳转是否继续。
beforeEach 中的 before 表示“之前”,each 表示“每一次”。因此它表示:每次路由跳转之前都执行一次检查。
路由配置可以参考 routes,而全局前置守卫通常写在创建路由实例之后。
为什么需要路由守卫
路由守卫主要用来处理进入页面前的统一逻辑:
- 判断用户是否已经登录
- 判断用户是否具有访问权限
- 未登录时跳转到登录页
- 修改页面标题
- 记录页面访问或跳转信息
语法
router.beforeEach(function (to, from) {
// 返回 true,允许继续跳转
return true;
});beforeEach() 接收一个回调函数:
to:准备进入的路由对象from:当前离开的路由对象- 返回
true:允许进入目标页面 - 返回
false:取消本次跳转 - 返回路由地址:取消当前跳转,并跳转到新的地址
基础例子
下面的例子要求用户登录后才能进入用户中心:
router.beforeEach(function (to, from) {
const isLogin = true;
if (to.path === "/user" && !isLogin) {
return "/login";
}
return true;
});当用户访问 /user 时,如果 isLogin 是 false,守卫会返回 /login,用户就会被带到登录页。
使用 meta 标记需要登录的路由
不建议把需要登录的路径全部写死在守卫中,可以在路由配置的 meta 中标记:
const routes = [
{
path: "/login",
component: () => import("./views/Login.vue")
},
{
path: "/user",
component: () => import("./views/User.vue"),
meta: {
requiresAuth: true
}
}
];然后在全局前置守卫中读取 to.meta.requiresAuth:
router.beforeEach(function (to) {
const isLogin = false;
if (to.meta.requiresAuth && !isLogin) {
return {
path: "/login",
query: {
redirect: to.fullPath
}
};
}
return true;
});这里将原本要访问的地址保存到 redirect 中,登录成功后可以再跳回原页面。
登录页白名单
登录页本身通常不能要求登录,否则用户会出现反复跳转的问题。使用 meta 标记需要登录的路由后,登录页默认不需要特殊处理:
router.beforeEach(function (to) {
const token = localStorage.getItem("token");
if (to.meta.requiresAuth && !token) {
return "/login";
}
return true;
});只有带有 requiresAuth: true 的路由才会检查 token,因此 /login 可以正常访问。
修改页面标题
meta 不只可以记录权限信息,也可以保存页面标题:
router.beforeEach(function (to) {
document.title = to.meta.title || "我的网站";
return true;
});对应的路由配置:
const routes = [
{
path: "/home",
component: () => import("./views/Home.vue"),
meta: {
title: "首页"
}
}
];常见返回值
| 返回值 | 作用 |
|---|---|
true | 允许本次路由跳转 |
false | 取消本次路由跳转 |
"/login" | 取消当前跳转,并跳转到登录页 |
{ name: "login" } | 按命名路由跳转到登录页 |
| 不返回内容 | 通常表示允许继续,但建议明确写出 return true |
特点
router.beforeEach()是全局守卫,所有路由跳转都会经过它to表示准备进入的路由,from表示当前离开的路由- 返回
true才表示明确允许继续跳转 - 返回
false可以取消跳转 - 返回新的路径或路由对象,可以把用户引导到其他页面
- 可以通过
to.meta读取路由配置中的自定义信息 - 登录状态可以从状态管理、
localStorage或其他数据源中读取 - 守卫中不要重复跳转到当前正在访问的页面,否则可能产生无限重定向
常见错误
忘记返回结果
router.beforeEach(function (to) {
if (to.meta.requiresAuth) {
console.log("需要登录");
}
});这种写法没有明确返回结果。更清晰的写法是根据条件返回地址或 true:
router.beforeEach(function (to) {
if (to.meta.requiresAuth && !isLogin) {
return "/login";
}
return true;
});登录页无限重定向
如果所有页面都无条件跳转到 /login,访问登录页时仍然会再次跳转到 /login。应该只在目标路由需要登录时进行判断:
if (to.meta.requiresAuth && !isLogin) {
return "/login";
}同时使用旧式 next
Vue Router 4 推荐直接通过返回值控制跳转。不要在同一个守卫中既使用 next(),又使用返回值:
router.beforeEach(function (to) {
if (to.meta.requiresAuth && !isLogin) {
return "/login";
}
return true;
});理解
可以把全局前置守卫理解成进入每个页面前都要经过的门卫。
用户准备进入页面时,to 是用户想去的地方,from 是用户当前所在的地方。守卫先检查用户是否满足条件:满足就返回 true 放行,不满足就返回登录页或其他页面。
meta 像是写在路由上的备注。它不直接改变页面,但可以告诉守卫“这个页面需要登录”或“这个页面的标题是什么”。这样路由配置负责描述页面,守卫负责统一处理规则,代码会更容易维护。
引出
全局前置守卫的判断逻辑主要依赖条件判断和函数回调,可以结合 JS 条件判断 与 JS 函数 继续理解。
当页面权限不只是“是否登录”,还涉及角色和操作权限时,还需要思考:路由权限应该如何分级,以及前端判断和后端权限校验应该怎样配合?