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` 访问组件实例 });