本次使用的是vue-admin-template-master模板
1.首先从后端那里获取用户权限的接口
2. 在路由导航里面每次跳转路由就向store派发一个获取用户权限接口
// 获取用户信息 权限
await store.dispatch('user/getInfo')
3.在store actions里面调取用户权限接口以及储存用户权限到state里面
// 获取用户权限
async getInfo({
commit,
state
}) {
let res = await getRole();
console.log(res);
if (res.status == 0) {
//vuex存储用户权限
commit('SET_USERINFO', res);
// 根据用户权限要展示的异步路由
commit('SET_RESULTASYNCROUTES', computeRouting(asyncRoutes, res.data));
}
},
// 存储用户信息
SET_USERINFO: (state, res) => {
// 路由权限
state.routes = res.data;
// 角色
state.role = res.role;
},
//state里面数据
onst getDefaultState = () => {
return {
token: getToken(),
// 路由权限
routes: [],
// 角色
role: '',
// 根据用户权限要展示的异步路由
resultAsyncRoutes: [],
// 要展示的所有路由
resultAllRoutes: [],
isAddRoutes: false
}
}
4.在router 里面把路由拆分为三部分:
constantRoutes //常量路由 不管用户有没有权限都可以访问的路由 比如:首页 登录页面
asyncRoutes //异步路由 根据用户的权限显示不同的路由
anyRoutes //任意路由 放404页面 最后合并的时候把他放到最后
// 常量路由
export const constantRoutes = [{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: {
title: '首页',
icon: 'dashboard'
}
}]
},
]
// 异步路由
export const asyncRoutes = [{
path: '/price',
name:'UserPrice',
component: Layout,
children: [{
path: 'index',
name: 'Price',
component: () => import('@/views/price/index'),
meta: {
title: '用户产品',
icon: 'form'
}
}]
},
{
path: '/statistics',
name: 'StatisticsManage',
component: Layout,
children: [{
path: 'index',
name: 'Statistics',
component: () => import('@/views/statistics/index'),
meta: {
title: '统计管理',
icon: 'form'
}
}]
},
{
path: '/totalSearch',
component: Layout,
name: 'Total',
children: [{
path: 'index',
name: 'totalSearch',
component: () => import('@/views/totalSearch/index'),
meta: {
title: '总量查询',
icon: 'form'
}
}]
},
]
// 任意路由 当路径出现错误的时候,重定向到404
export const anyRoutes =
// 404 页面必须放在末尾!!!
{
path: '*',
redirect: '/404',
hidden: true
}
5.store user.js文件里面
引入已经分配好的路由以及router实例
import {
resetRouter,
asyncRoutes,
constantRoutes,
anyRoutes
} from '@/router'
import router from '@/router'
6.根据接口返回来的用户权限来过滤出我们要展示的路由
// 根据用户权限要展示的异步路由
commit('SET_RESULTASYNCROUTES', computeRouting(asyncRoutes, res.data));
computeRouting函数用来过滤出要展示的路由
根据路由的name参数来进行过滤
// 过滤出要展示的路由
const computeRouting = (asyncRoutes, routes) => {
return asyncRoutes.filter(item => {
if (routes.indexOf(item.name) != -1) {
// 使用递归过滤子路由
if (item.children && item.children.length) {
item.children = computeRouting(item.children, routes);
}
return true;
}
})
}
合并要展示的所有路由 使用addRoutes添加新的路由 最后储存到state里面
// 根据用户权限要展示的异步路由
SET_RESULTASYNCROUTES: (state, asyncRoutes) => {
// 储存当前用户的异步路由
state.resultAsyncRoutes = asyncRoutes;
// 合并要展示的所有的路由
state.resultAllRoutes = constantRoutes.concat(state.resultAsyncRoutes, anyRoutes);
// 给路由器添加新的路由
router.addRoutes(state.resultAllRoutes);
state.isAddRoutes = true;
}
7.在src/layout/components/Sidebar/index.vue文件里面遍历分配好的路由
<sidebar-item
v-for="route in routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
routes() {
// return this.$router.options.routes
// 遍历仓库中计算好的路由
return this.$store.state.user.resultAllRoutes;
},
最后来说说做好权限路由之后遇到刷新页面白屏的问题
引起白屏的原因是使用addRoutes导致的
解决方法:
store user state里面 定义几个变量 初始值为false
const getDefaultState = () => {
return {
isAddRoutes: false
}
}
给路由器添加好新的路由之后让他的值为true
// 根据用户权限要展示的异步路由
SET_RESULTASYNCROUTES: (state, asyncRoutes) => {
// 储存当前用户的异步路由
state.resultAsyncRoutes = asyncRoutes;
// 合并要展示的所有的路由
state.resultAllRoutes = constantRoutes.concat(state.resultAsyncRoutes, anyRoutes);
// 给路由器添加新的路由
router.addRoutes(state.resultAllRoutes);
state.isAddRoutes = true;
}
在permission.js全局路由导航文件里面
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({
path: '/'
})
NProgress.done()
} else {
const hasGetUserInfo = store.getters.name
if (hasGetUserInfo) {
next()
} else {
try {
if (!store.state.user.isAddRoutes) {
// 获取用户信息 权限
await store.dispatch('user/getInfo')
// next()
// 确保路由完整性,设置replace 为true 这样导航就不会留下历史记录。
next({
...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
replace: true // 重进一次, 不保留重复历史
})
} else {
next()
}
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
next({
...to, // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
replace: true // 重进一次, 不保留重复历史
})
最后在退出登录的时候重置路由
router文件:
// 重置路由
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // 重新设置路由的可匹配路径
}
在store/user.js文件里面
// 退出
logout({
commit,
state
}) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
removeToken() // must remove token first
// 退出移除用户ID
window.localStorage.removeItem('userId')
window.localStorage.removeItem('username')
// 重置路由
resetRouter()
commit('RESET_STATE')
resolve()
}).catch(error => {
reject(error)
})
})
},