路由守卫(Route Guard)是 Vue.js 提供的一种机制,用于在路由改变时,控制是否允许用户访问该路由。它可以让开发者在路由发生改变之前或之后执行一些操作,例如验证用户是否有权限访问该路由、跳转到登录页、记录路由访问日志等。在 Vue.js 中,路由守卫由全局守卫、路由独享守卫和组件内守卫三种形式。
全局路由守卫
全局路由守卫会在所有路由切换中都会触发,可以使用router.beforeEach
方法来定义全局守卫:
const router = new VueRouter({ routes })
router.beforeEach((to, from, next) => {
// to: 即将进入的路由
// from:当前导航正要离开的路由
// next: 一定要调用该方法来 resolve 这个钩子
if (to.meta.auth && !isAuthenticated) {
// 需要身份验证,未通过验证
next('/login')
} else {
next()
}
})
在这个例子中,我们使用 router.beforeEach
方法定义了全局守卫。在守卫中,我们可以访问即将进入的路由 to
和当前导航正要离开的路由 from
。我们可以根据需要进行处理,例如进行身份验证,验证未通过则跳转到登录页;如果身份验证通过,则通过调用 next
方法来 resolve 这个钩子,让导航继续进行。
路由独享守卫
路由独享守卫只会在某个具体路由切换时触发,可以在路由配置对象中使用 beforeEnter
方法来定义独享守卫:
const router = new VueRouter(
{ routes: [{
path: '/home',
component: Home,
beforeEnter: (to, from, next) => {
// ...
}
} ]
})
在这个例子中,我们在路由配置对象中使用 beforeEnter
方法定义了路由独享守卫。在守卫中,我们可以根据需要进行处理,例如进行身份验证、日志记录等操作,然后通过调用 next
方法来决定是否允许进入该路由。
组件内守卫
组件内守卫可以在某个组件内部使用,可以使用 beforeRouteEnter
、beforeRouteUpdate
和 beforeRouteLeave
来定义组件内守卫。
beforeRouteEnter
守卫beforeRouteEnter
守卫可以在组件创建时调用,在组件实例化之前进行一些操作,例如获取数据、判断用户权限等。
const Home = {
template: '<div>{{ message }}</div>',
beforeRouteEnter (to, from, next) {
// ...
next(vm => {
// ...
})
}, data () {
return { message: 'Hello Vue!' }
}
}
在这个例子中,我们在组件定义对象中使用 beforeRouteEnter
方法定义了组件内守卫。在守卫中,我们可以根据需要进行操作,例如获取数据、判断用户权限等。需要注意的是,beforeRouteEnter
守卫只有在组件被激活时才会被调用,因此在这里无法访问组件实例 this
。
beforeRouteUpdate
守卫beforeRouteUpdate
守卫可以在组件路由参数发生变化时调用,在组件实例化之后进行一些操作。
const Home = {
template: '<div>{{ message }}</div>',
beforeRouteUpdate (to, from, next) {
// ...
next()
}, data () {
return { message: 'Hello Vue!' }
}
}
在路由守卫中,next
方法是用于告知路由导航守卫它能否继续执行的方法。next
方法可以传递一个参数,这个参数的类型可以是以下三种之一:
- 没有参数,表示允许路由导航继续执行。
next();
- 传递一个
false
参数,表示阻止路由导航。
next(false);
- 传递一个
to
参数,表示请求路由导航到一个不同的 URL。
next('/login');
需要注意的是,在使用 next
方法时,我们需要保证它一定会被调用,否则路由导航会永远被阻塞。通常情况下,在执行完某些操作后,需要调用 next
方法来通知路由守卫执行下一步操作。
以下是一个使用 next
方法的示例:
router.beforeEach((to, from, next) => {
// 判断用户是否已登录
if (localStorage.getItem('token')) {
next();
} else {
next('/login');
}
});
在这个示例中,我们使用 router.beforeEach
方法定义了一个全局的路由守卫。在守卫中,我们判断用户是否已经登录,如果已经登录则调用 next
方法,否则将用户导航到登录页面。
需要注意的是,在某些情况下,我们需要异步执行某些操作后再调用 next
方法。在这种情况下,我们可以使用 Promise 来实现异步操作,然后在异步操作完成后再调用 next
方法,例如:
router.beforeEach((to, from, next) => {
// 异步获取用户信息
getUserInfo().then(userInfo => {
// 判断用户是否已登录
if (userInfo.isLoggedIn) {
next();
} else {
next('/login');
}
});
});