Vue 3 的导航守卫与 Vue 2 相比,在 API 和使用方式上并没有太大的变化,但 Vue 3 的响应式系统和 Composition API 为导航守卫提供了更多的灵活性。
以下是 Vue 3 中常见的几种导航守卫:
1. 全局前置守卫
全局前置守卫在路由跳转前执行。你可以使用 【router.beforeEach】 注册一个全局前置守卫:
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [/* ...你的路由对象... */],
})
router.beforeEach((to, from, next) => {
// 在这里执行你的逻辑
// 例如,检查用户是否已登录
const isLoggedIn = /* ...获取是否登录的逻辑.. */;
if (isLoggedIn) {
next(); // 允许路由跳转
} else {
next('/login'); // 阻止路由跳转,并重定向到登录页面
}
})
2. 全局后置守卫
全局后置守卫在路由跳转后执行。你可以使用 【router.afterEach】 注册一个全局后置守卫:
router.afterEach((to, from) => {
// 在这里执行你的逻辑
// 例如,发送一个分析事件
analytics.trackPageView(to.path);
})
3. 路由独享的守卫
你可以在每个路由配置对象中定义 【beforeEnter 】守卫:
const routes = [
{
path: '/user/:id',
component: User,
beforeEnter: (to, from, next) => {
// 在这里执行你的逻辑
// 例如,检查用户是否有权限访问该页面
const hasPermission = /* ...获取你的权限.. */;
if (hasPermission) {
next();
} else {
next('/forbidden');
}
},
},
// ... 其他路由
]
4. 组件内的守卫
在组件内部,你可以使用 【beforeRouteEnter、beforeRouteUpdate 和 beforeRouteLeave】守卫:
<script>
import { onBeforeRouteEnter, onBeforeRouteUpdate, onBeforeRouteLeave, ref } from 'vue';
export default {
setup() {
const someData = ref(null);
// 组件被渲染前调用
onBeforeRouteEnter((to, from, next) => {
// 注意:这里不能访问组件的响应式状态或 `setup` 中的局部变量
// 因为组件实例还没有被创建
next(vm => {
// 当组件实例创建后,可以通过 vm 访问
// 但通常我们不需要这么做,因为守卫逻辑可以在 `setup` 中处理
});
});
// 当前路由改变,但组件被复用时调用
onBeforeRouteUpdate((to, from, next) => {
// 可以访问 `setup` 中的响应式状态
console.log('Route updated:', to.path);
next();
};
// 导航离开组件时调用
onBeforeRouteLeave((to, from, next) => {
// 可以访问 `setup` 中的响应式状态
if (someData.value) {
const answer = window.confirm('你确定要离开吗?你的数据尚未保存。');
if (answer) {
next();
} else {
next(false);
}
} else {
next();
}
};
// 组件的逻辑...
// 返回响应式状态或其他计算属性、方法等
return {
someData,
// ...
};
},
};
</script>
注意项
1. 注意next的使用,不能在一个导航钩子内调用两次!!
以下错误示例:
// 错误示例
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// 如果用户未能验证身份,则 `next` 会被调用两次
next()
})
2. next 函数必须被调用,否则导航将不会解析或更新 URL。
3. 在全局守卫和路由独享的守卫中,next 函数接受一个位置参数,表示要导航到的下一个位置。
next({ name: 'Login' }) //导航到name为Login的路由
4. 如果传入 false,则导航会被终止。
next(false) //终止导航
5. 在组件内的守卫中,beforeRouteEnter 守卫的 next 函数接受一个回调函数作为参数,
该回调函数在组件实例被创建后执行。如下:
next(vm => {
// 当组件被渲染后,你可以通过 `vm` 访问组件实例
});