官网参考:导航守卫 | Vue Router
一、Vue 路由守卫的作用
1、权限控制
检查用户是否已登录,如果未登录则重定向到登录页面。
根据用户角色限制访问某些路由。
2、数据预加载
在进入路由前加载必要的数据,确保页面渲染时有完整的数据。
3、导航拦截
在某些条件下阻止用户离开当前页面(例如表单未保存时)。
4、日志记录
记录用户访问的路由,用于分析或调试。
5、动态路由
根据条件动态添加或修改路由。
二、根据路由守卫更改页面的名称
1、引入基本语法
首先输出一下to和from参数
//设置路由守卫
router.beforeEach((to, from, next) => {console.log('to', to)console.log('from', from)next()
})
可查看到一个参数meta.title,其可对标题名称进行修改
2、设置系统总标题
直接设置一个变量即可
//设置系统标题
const SystemTitle = 'SMS后台管理系统';
3、设置路径的标题
在之前设置的项中,设置meta下title的名称
只用设置外层页面的标题,主要的含导航内容的页面暂不修改
4、修改页面标题
修改页面的标题的方法为document.title
//设置系统标题
const SystemTitle = 'SMS后台管理系统';
//设置路由守卫
router.beforeEach((to, from, next) => {if(to.meta.title){document.title = to.meta.title + '-' + SystemTitle}next()
})
5、测试效果
三、权限控制
主要针对需要登录的页面,
- 没有token
- 在需要登录的页面-跳转登录页面
- 不需要登录的页面-放行(可以继续执行)
- 有token
- 如果在登录页面-跳转到主页面
- 如果没在登录页面-pinia读取用户信息
1、基本信息设置
首先获取token,查看token是否存在,如果不存在需要跳转到登录页面
①引入token获取
import { getToken } from '@/utils/token';
②获取token
const token = getToken();
③设置无需登录的页面
取name名称,因为404页面的path是一个变化量(path: '/:pathMatch(.*)*',),不能确定
//设置一个不需要进行登录的页面数组
const NoLogin = [ 'login','not-found','test']
2、token不存在情况
①无需登录的页面
无需登录的页面,是可以不需要token的,那么就可以直接放行
//在NoLogin数组中,表示不需要登录,就直接放行
if (NoLogin.includes(to.name)) {next()
}
②需要登录的页面
需要登录的页面,但没有token表示登录状态可能过期等情况,需要重新条会登录页面进行登录
//如果不在NoLogin数组中,就表示需要登录,没有token就跳转到登录页面
else{next({ name: 'login' })
}
3、token存在情况
①在登录login页面
需要进行,在登录页面,且存在token,表示可以直接跳转到主页面
//如果在登录页面,就跳转到首页
if(to.name == 'login'){next({ name: 'main' })
}
②在其他页面
需要通过pinia获取用户信息
Ⅰ简单介绍
Pinia 是 Vue.js 的官方推荐状态管理库。使用 Pinia 的主要目的是为了更简单、更灵活地管理应用程序的状态。
Ⅱ参考pinia
pinia参考:定义一个 Store | Pinia
初始创建vue项目的时候,选择pinia的会有相关数据,如果没有选择pinia可进入官网参考进行安装
安装参考:vue3:pinia安装-CSDN博客
Ⅲ使用pinia获取用户状态信息
建立user.js
在src/stores建立user.js的项目,如果是初始vue项目的话,会自动生成counter.js如下
修改代码
复制counter.js的代码到src/stores/user.js,没有就码字
先清除不要的代码
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', () => {return { count, doubleCount, increment }
})
修改名称
根据之前给的例子,可以进行用户信息的获取,设值
路由引用
在路由中的相关位置使用pinia进行数据获取/设置
路径:src/router/index.js
引入方法
import { userStore } from '@/stores/user'
获取用户信息,如果存在账号信息,就放行(有token,有账号信息,可放行)
//读取用户信息
const userstore = userStore();
if (userstore.username) {//放行next();
}
没有用户信息,但存在token,需要对用户信息进行查询
- 成功获取用户信息:需要更新store的用户信息,并且更新新的token
- 没获取用户信息:删除token,并回到登录页面,需重新登录
apifox建立查询用户信息的接口
新建接口
注意:使用的是get
新建期望
返回用户的基本信息
api封装
在src/api/user.js中写入获取用户信息的get方法
接口方法引入
逻辑端执行没有用户信息,存在token功能
else {//如果token存在,用户信息没查询到就去请求用户信息var res = await getuserinfo();//请求之后,如果请求成功,就设置token,设置用户信息,放行,如果请求失败,就删除token,跳转到登录页面if(res.code == 1){//设置token和用户信息setToken(res.token);//将用户信息设置到store中userstore.setUserinfo(res.data)//放行next();}else{//删除tokendelToken();//跳转到登录页面next({ name: 'login' })}
}
注意:
defineStore的第一个参数是唯一id,如果定义别的store,此参数不能重复
4、测试效果
①测试token不存在,看是否跳转到登录页面
首先在主页页面,可以查看到基本token信息
右击删除token
再刷新此页面 ,成功跳回login页面
②测试token存在,再登录页面是否会直接进入主页面
在主页面,存在token信息
将路径改为login
页面再次回到主页面
四、完整代码
1、pinia获取/设置用户信息
src/stores/user.js
import { computed, reactive } from 'vue'
import { defineStore } from 'pinia'export const userStore = defineStore('userinfo', () => {//声明用户信息const userinfo = reactive({});//对象//获取用户名等。由于用户名是通过用户信息获取的,所以需要一个计算属性const username = computed(() => userinfo.name);//设值用户信息const setUserinfo = (info) => {//对象使用assign,如果userInfo中有相同的key,则info覆盖userInfo的key信息,把之前有的信息进行更换)Object.assign(userinfo, info)}return { userinfo, username ,setUserinfo}
})
2、获取用户信息
src/api/user.js
import { post , get } from '@/utils/request';// 登录
export function login(data) {return post('/user/login', data);
}
//重置密码-通过手机号
export function repwd(data) {return post('/user/repassword', data);
}
//获取用户信息
export function getuserinfo() {return get('/user/getuserinfo');
}
3、路由信息
src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import { getToken, setToken, delToken } from '@/utils/token';
import { userStore } from '@/stores/user'
import { getuserinfo } from '@/api/user';
// 引入路由
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [//将子项全部存入一个大的路由中layout/index.vue,页面刚进入时调用的时layout/index.vue,在为导航条,默认显示页面/home的内容{path: '/',name: 'main',component: () => import('@/layout/index.vue'),redirect: '/home',children: [{path: '/home',name: 'home',component: HomeView},{path: '/about',name: 'about',component: () => import('../views/AboutView.vue')},]},//登录{path: '/login',name: 'login',component: () => import('@/views/LoginView.vue'),meta: {title: '登录'}},//测试页面{path: '/test',name: 'test',component: () => import('@/views/TestView.vue'),meta: {title: '测试页面'}},//404{path: '/:pathMatch(.*)*',name: 'not-found',component: () => import('@/views/NotFoundView.vue'),meta: {title: '页面未找到'}},],
})//设置系统标题
const SystemTitle = 'SMS后台管理系统';
//设置一个不需要进行登录的页面数组
const NoLogin = ['login', 'not-found', 'test']
//设置路由守卫
router.beforeEach(async(to, from, next) => {if (to.meta.title) {//拼接新标题var newtitle = to.meta.title + '-' + SystemTitledocument.title = newtitle}// 判断是否登录const token = getToken();//如果token不存在if (!token) {//在NoLogin数组中,表示不需要登录,就直接放行if (NoLogin.includes(to.name)) {next()}//如果不在NoLogin数组中,就表示需要登录,没有token就跳转到登录页面else {next({ name: 'login' })}}//token存在else {//如果在登录页面,就跳转到首页if (to.name == 'login') {next({ name: 'main' })}else {//读取用户信息const userstore = userStore();console.log(userstore)if (userstore.username) {//放行next();}else {//如果token存在,用户信息没查询到就去请求用户信息var res = await getuserinfo();console.log(res);//请求之后,如果请求成功,就设置token,设置用户信息,放行,如果请求失败,就删除token,跳转到登录页面if(res.code == 1){//设置token和用户信息setToken(res.data.token);//将用户信息设置到store中userstore.setUserinfo(res.data)//放行next();}else{//删除tokendelToken();//跳转到登录页面next({ name: 'login' })}}}}
})export default router