Vue Router 实现登录后跳转到之前想要访问的页面
CJc_3103 人气:0简介
该功能主要用于判定用户权限,在用户无权限时重定向至登录页,并在用户完成登录后,再定向至用户之前想要访问的路由;或者用户在任意路由点击登录时,登录成功后返回当前路由。是一个很常规的小功能。
简单示例
本文仅演示路由跳转和导航守卫相关代码的实现,不包含具体的权限验证和登录请求。
实现该功能主要分为四步:
- 在登录组件的路由配置对象中添加
props: route => ({ redirect: route.query.redirect })
- 在登录组件中使用 props 接收参数
props: ['redirect']
,同时在登录事件完成时判定路由参数并跳转:
props: ['redirect'], ... handleLogin() { this.$store.dispatch('LOGIN', { somePramsHere }) .then(() => { this.$router.push( this.redirect ? { path: this.redirect } : { name: 'Home' } ); }) .catch((err) => { // 登录失败 }); },
在其他路由的登录入口添加相应的 rediect 参数,如首页的登录链接:
<router-link :to="{ name: 'Login', query: { redirect: $route.fullPath }, }" ><span class="login">登录</span></router-link>
在路由守卫中添加相应的判定逻辑,当用户不具备权限时,重定向至登录页:
import router from './index'; import store from '@/store/index'; import whiteList from './whiteList'; router.beforeEach((to, from, next) => { if (!store.state.token) { // 未登录 if ( to.matched.length > 0 && to.matched.some((record) => whiteList.includes(record.path)) // 此处还可添加用户权限验证相关逻辑,如 to.matched.some(record => record.requiresAuth) ) { // 该路由不要求用户登录,继续完成导航 next(); } else { // 用户未登录,且目标路由不在白名单中,重定向至登录页 next({ name: 'Login', query: { redirect: to.fullPath } }); } else { ... // 已登录时的路由守卫判定 } } }
补充用户退出时的处理
由于导航守卫只有在路由变化时才会被触发,而使用 $router.replace() 模拟刷新并不会触发导航守卫(push() 也不行),因为 VueRouter 不允许进入相同的路由,这是其内部机制,我们无法在外部干涉。
因此,只能在用户退出成功时,手动加入与导航守卫相同的判定逻辑,若在白名单之内或拥有相应的路由权限,则留在当前路由;若不符合条件,则重定向至登录页:
退出相关组件
import whiteList from '@/store/whiteList'; import routePaths from '@/store/routePaths'; ... handleLogoutRedirect() { let location = {}; if ( !whiteList.includes(this.routePath) && !whiteList.includes(routePaths[this.routeName]) ) { location = { name: 'Login', query: { redirect: this.routePath } }; // 注意这里,需要手动带上当前路径,否则重新登录后只能到首页 this.$router.push(location); } // 当前路由在白名单之内的,不需要跳转,留在当前路由即可 }, handleLogout() { this.$store .dispatch('LOGOUT') .then(() => { this.handleLogoutRedirect(); }) .catch((err) => err); }, ...
注意,我在顶部导入了一个 routePaths 对象。由于搜索页等组件是带有 params 参数的,若想要判定当前路由是否属于白名单,需要使用路由配置对象中的完整 path 字符串,比如搜索页是 /search/:keyword?
,那么白名单数组和 routePaths 对象里都需要使用这个字符串。此处为了匹配的方便,使用路由组件的 name 属性作为 routePaths 的 key。示例:
routePaths.js
// 其他路由若是 path 不带 params 参数的,可以不用配置,像上述代码那样分开判定即可 const routePaths = { Search: '/search/:keyword?', } export default routePaths;
进阶
在任意路由点击登录,将当前路由和路由参数都带给登录组件,登录成功后返回之前的路由并携带全部路由参数。
此处的导航守卫、以及带有登录链接或跳转至登录页功能的组件代码无需改动,只需要修改路由配置对象和登录组件。
首先,定义路由的配置对象时,将登录组件的路由 props 改为:
props: route => { let params = route.params, query = route.query; // 这里不能解构 route 对象,否则拿不到值 const redirect = query.redirect; Reflect.deleteProperty(query, 'redirect'); // 原本的 query 对象不带 redirect 属性,因此需要删除 return { redirect, params, query } },
其次,登录成功时,给路由跳转添加 prams 和 query 参数
props: ['redirect', 'params', 'query'], ... handleLogin() { this.$store .dispatch('LOGIN', { phone: this.phone, password: this.password }) .then((data) => { this.$router.push( this.redirect ? { path: this.redirect, params: this.params, query: this.query } : { name: 'Home' } ); }) .catch((err) => { console.log('登录失败:', err); }); },
加载全部内容