activemenu怎么拼 vue_vue-element-admin登录逻辑,以及动态添加路由,显示侧边栏
这段时间在研究element-admin,感觉这个库有许多值得学习的地方,我学习这个库的方法是,先看它的路由,顺着路由,摸清它的逻辑,有点像顺藤摸瓜。
这个库分的模块非常清晰,适合多人合作开发项目,但是如果一个人去用这个库开发后台,步骤显的有点繁琐,特别是调用后端接口,之前一个方法就调用到了,但是用这个库,需要先后分几步调用。
比如说调用一个登陆接口:点击登陆按钮----》调用store中的方法----》调用api中对应登陆的方法---》request.js中封装的axios方法
4步!!!!,让我看来确实是有点繁琐,这个问题到后面解决,通过自己封装的axios方法,直接调用后台接口,目前不知道会不会遇到其它问题。好了,接下来进入正题!!!
接下来先介绍一下,element-admin的登录逻辑
1、先看登录方法里写什么:
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true;
//调用user模块红的login
console.log("点击登陆按钮")
this.$store.dispatch('user/login', this.loginForm).then(() => {
console.log("登录成功");
this.$router.push({ path: this.redirect || '/' });
this.loading = false;
}).catch(() => {
this.loading = false;
})
} else {
console.log('error submit!!');
return false;
}
})
}
通过上面红色代码,可以看出,点击过登录按钮后,调用了$store里的一个方法,名叫login
2、下面来看看$store里的这个login方法:
import { login, logout, getInfo,self} from '@/api/user'
const actions = {
// user login
login({ commit }, userInfo) {
const { username, password } = userInfo;
return new Promise((resolve, reject) => {
console.log("vuex中的请求")
login({ username: username.trim(), password: password }).then(response => {
console.log('vuex中')
console.log(response);
const { data } = response;
commit('SET_TOKEN', data.token);//存在vueX中
setToken(data.token);//存在cookie中
resolve();
}).catch(error => {
console.log(error);
reject(error);
})
})
},
咿,怎么两个login,熟悉vuex的话应该知道,第一个login是$store中的方法,第二个login方法是,api里的login方法,用来调用接口的
3、再来看看api中的login方法:
import request from '@/utils/request'
export function login(data) {
return request({
url: '/user/login',
method: 'post',
data
})
}
上面是api中的login方法,它调用了request.js,request.js是封装了axios,是用来请求后台接口的,如果这个接口请求成功了,就回到了第一步中的.then()方法中
代码是,路由跳转到首页,进入正式页面!!!
重点来了!!!
之所以是称之为权限,也就是必须满足一定的条件才能够访问到正常页面,那么如果不满足呢?如果我没有token,让不让我进正常页面呢??
肯定是不让的,那我没有token,该去哪?答案是还待在登录页,哪都去不了,那么这些处理应该在哪写呢?答案是,permission.js模块
这个js在main.js引入,其实就是个路由拦截器:来看看它的代码:
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar 一个进度条的插件
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration 是否有转圈效果
const whiteList = ['/login'] // 没有重定向白名单
router.beforeEach(async(to, from, next) => {
// 开始进度条
NProgress.start()
// 设置页面标题
document.title = getPageTitle(to.meta.title)
// 确定用户是否已登录
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// 如果已登录,则重定向到主页
next({ path: '/' })
NProgress.done()
} else {
const hasGetUserInfo = store.getters.name;
console.log(hasGetUserInfo);
if (hasGetUserInfo) {
console.log("有用户信息");
next();
} else {
console.log("无用户信息")
try {
// 获得用户信息
await store.dispatch('user/getInfo');
//实际是请求用户信息后返回,这里是模拟数据,直接从store中取
const roles=store.getters.roles;
store.dispatch('permission/GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
router.options.routes=store.getters.routers;
next({ ...to, replace: true });// hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
// next()
} catch (error) {
// 删除token,进入登录页面重新登录
await store.dispatch('user/resetToken');
Message.error(error || 'Has Error');
next(`/login?redirect=${to.path}`);
NProgress.done();
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// 在免费登录白名单,直接去
next()
} else {
// 没有访问权限的其他页面被重定向到登录页面。
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
router.afterEach(() => {
// 完成进度条
NProgress.done()
})
一看代码好多,不过不要怕,我来分析一下它的情况,不就是点if else嘛
从上面代码看,每次路由跳转,都要从cookie中取token,
那么可以分两种情况,有token和无token
有token:再看看是不是去登录页的,登录页肯定不能拦截的,如果是登录页就直接放行。如果不是登录页,就要看看本地有没有用户信息,看看cookie中有没有用户信息(不一定是token,也可能是localstorage)。如果有用户信息,放行。如果没有用户信息,就调用接口去获取登录信息,然后后面还有一点代码,涉及到了动态添加路由(这里先说到这,后面具体说动态添加权限路由的事)。获取到用户信息后放行。如果在获取用户信息的过程中报错,则回到登录页
无token:先看看用户要进入的页面是不是在白名单内,一般登录、注册、忘记密码都是在白名单内的,这些页面,在无token的情况下也是直接放行。如果不在白名单内,滚回登录页。
以上就是element-admin的登录逻辑了。不知道能否帮助到你,但是写下来,让自己的思路更清晰,也是不错的。
下面来说一下,element-admin的动态权限路由,显示侧边栏是什么逻辑
首先要了解一下,侧边栏是如何渲染出来的,看看layout/components/slibar/index.vue有这样一段代码:
计算属性中有这样一段代码:
routes() {
return this.$router.options.routes
},
这个routes,是路由的元信息!!!是一个数组
看到这就应该明白,侧边栏是如何渲染出来的,
再来看看router.js里的代码:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'
/**
* 注意: 子菜单只在路由子菜单时出现。长度> = 1
* 参考网址: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
*
* hidden: true 如果设置为true,项目将不会显示在侧栏中(默认为false)
* alwaysShow: true 如果设置为true,将始终显示根菜单
* 如果不设置alwaysShow, 当项目有多个子路由时,它将成为嵌套模式,否则不显示根菜单
* redirect: noRedirect 如果设置noRedirect,则不会在面包屑中重定向
* name:'router-name' the name is used by (must set!!!)
* meta : {
roles: ['admin','editor'] 控制页面角色(可以设置多个角色)
title: 'title' 名称显示在侧边栏和面包屑(推荐集)
icon: 'svg-name' 图标显示在侧栏中
breadcrumb: false 如果设置为false,则该项将隐藏在breadcrumb中(默认为true)
activeMenu: '/example/list' 如果设置路径,侧栏将突出显示您设置的路径
}
*/
/**
* constantRoutes
* 没有权限要求的基本页
* 所有角色都可以访问
* 不需要动态判断权限的路由
*/
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/self',
children: [{
path: 'self',
name: 'Self',
component: () => import('@/views/self/index'),
meta: { title: '首页', icon: 'dashboard' }
}]
},
{
path: '/example',
component: Layout,
redirect: '/example/table',
name: 'Example',
meta: { title: 'Example', icon: 'example' },
children: [
{
path: 'table',
name: 'Table',
component: () => import('@/views/table/index'),
meta: { title: 'Table', icon: 'table'}
},
{
path: 'tree',
name: 'Tree',
component: () => import('@/views/tree/index'),
meta: { title: 'Tree', icon: 'tree',breadcrumb: true},
hidden: false,//在侧边栏上显示 true为不显示 当父路由的字路由为1个时,不显示父路由,直接显示子路由
alwaysShow:false,//默认是false 设置为true时会忽略设置的权限 一致显示在跟路由上
}
]
},
{
path: '/form',
component: Layout,
children: [
{
path: 'index',
name: 'Form',
component: () => import('@/views/form/index'),
meta: { title: 'Form', icon: 'form' }
}
]
},
{
path: '/nested',
component: Layout,
redirect: '/nested/menu1',
name: 'Nested',
meta: {
title: 'Nested',
icon: 'nested'
},
children: [
{
path: 'menu1',
component: () => import('@/views/nested/menu1/index'), // Parent router-view
name: 'Menu1',
meta: { title: 'Menu1' },
children: [
{
path: 'menu1-1',
component: () => import('@/views/nested/menu1/menu1-1'),
name: 'Menu1-1',
meta: { title: 'Menu1-1' }
},
{
path: 'menu1-2',
component: () => import('@/views/nested/menu1/menu1-2'),
name: 'Menu1-2',
meta: { title: 'Menu1-2' },
children: [
{
path: 'menu1-2-1',
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
name: 'Menu1-2-1',
meta: { title: 'Menu1-2-1' }
},
{
path: 'menu1-2-2',
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
name: 'Menu1-2-2',
meta: { title: 'Menu1-2-2' }
}
]
},
{
path: 'menu1-3',
component: () => import('@/views/nested/menu1/menu1-3'),
name: 'Menu1-3',
meta: { title: 'Menu1-3' }
}
]
},
]
},
{
path: 'external-link',
component: Layout,
children: [
{
path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
meta: { title: 'External Link', icon: 'link' }
}
]
},
{
path: '/self',
component: Layout,
children: [
{
path: 'index',
name: 'self',
component: () => import('@/views/self'),
meta: { title: 'self', icon: 'form' }
}
]
},
// 404页面必须放在最后!!
// { path: '*', redirect: '/404', hidden: true }
]
// 创建路由
const createRouter = () => new Router({
// mode: 'history', // 需要服务支持
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
var router = createRouter()
// 重置路由
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
//异步挂载的路由
//动态需要根据权限加载的路由表
export const asyncRouterMap = [
{
path: '/permission',
component: Layout,
name: 'permission',
redirect: '/permission/index222',
meta: {title:'permission', role: ['admin','super_editor'] }, //页面需要的权限
children: [
{
path: 'index222',
component: () => import('@/views/self'),
name: 'index222',
meta: {title:'权限测试1',role: ['admin','super_editor'] } //页面需要的权限
},
{
path: 'index333',
component: () => import('@/views/self'),
name: 'index333',
meta: {title:'权限测试2',role: ['admin','super_editor'] } //页面需要的权限
}
]
},
{ path: '*', redirect: '/404', hidden: true }
];
export default router
注意以上代码中红色的代码,这个routes中分两块路由配置,一块是固定的,无权限的路由配置,也就是不管是管理员身份,还是超级管理员身份,都会显示的路由配置。
第二块是,带权限的路由配置,根据用户权限来显示侧边栏。注意,带权限的配置里的meta中都有role项,代表是权限
首先,我们在获取用户信息时,会得到这个用户有哪些权限,是一个数组,假如是这样的
commit('SET_ROLES',['admin','super_editor']);//自定义权限
这个用户的权限有这些(admin、super_editor),然后再根据用户权限来筛选出符合的动态添加的路由,
什么时候筛选呢?
这就用到登录时的拦截器了,上面遇到过,就在哪执行,来看看那里都是写了一些什么代码:
拿到这看看:
// 获得用户信息
await store.dispatch('user/getInfo');
//实际是请求用户信息后返回,这里是模拟数据,直接从store中取
const roles=store.getters.roles;
store.dispatch('permission/GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
router.options.routes=store.getters.routers;
next({ ...to, replace: true });// hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
routes其实就是上面的两个权限组成的数组,然后传入了GenerateRoutes方法内,(注意es6语法,看不懂的去了解一下es6),再看看GenerateRoutes中的代码:
import { asyncRouterMap, constantRoutes } from '@/router';
function hasPermission(roles, route) {
if (route.meta && route.meta.role) {
return roles.some(role => route.meta.role.indexOf(role) >= 0)
} else {
return true
}
}
const permission = {
namespaced: true,
state: {
routers: constantRoutes,
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers;
state.routers = constantRoutes.concat(routers);
}
},
actions: {
GenerateRoutes({ commit }, data) {//roles是用户所带的权限
return new Promise(resolve => {
const { roles } = data;
const accessedRouters = asyncRouterMap.filter(v => {
// if (roles.indexOf('admin') >= 0) {
// return true;
// };
if (hasPermission(roles, v)) {
if (v.children && v.children.length > 0) {
v.children = v.children.filter(child => {
if (hasPermission(roles, child)) {
return child
}
return false;
});
return v
} else {
return v
}
}
return false;
});
commit('SET_ROUTERS', accessedRouters);
resolve();
})
}
}
};
export default permission;
GenerateRoutes方法办了一件事,就是把动态路由配置里符合用户权限的配置筛选出来,组成一个数组,然后,和固定路由合并到了一起,存到了vuex中,
然后调用了这两句代码:
router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
router.options.routes=store.getters.routers;
router.addRoutes()方法是,动态添加路由配置,参数是符合路由配置的数组,
然后将路由元信息,变成合并后的路由元信息,因为渲染侧边栏需要用到,
这两句代码,顺序不能变,缺一不可,缺了addRoutes,点击侧边栏的动态路由会无反应,缺了options,侧边栏显示不出来动态添加的路由!!!!
以上就是element-admin的动态路由了,睡觉。。。。
标签:vue,admin,router,element,meta,store,import,path,路由
来源: https://www.cnblogs.com/fqh123/p/11094296.html
activemenu怎么拼 vue_vue-element-admin登录逻辑,以及动态添加路由,显示侧边栏相关推荐
- 【前端】Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单、动态添加路由
文章目录 目标 代码 0.动态地显示菜单:store 1.动态注册路由 2.解决刷新后摆平问题 总代码 本篇修改的代码文件 tab.js 参考视频: VUE项目,VUE项目实战,vue后台管理系统,前 ...
- element实现form表单动态添加email效果
前言: vue中使用element实现form表单动态添加email效果 效果: 实现步骤: 实现源代码: <template><div><el-form ref=&qu ...
- vue的动态路由(登录之后拿到动态路由通过addRouters()动态添加路由)
登录后我们拿到路由动态路由,后端传的数据可能为这个 {path: '/index',meta: {title: '首页',icon: 'icon-shouye',tab_index: 0, //给头部 ...
- vue element admin登录方式切换(密码登录或短信登录)
显示结果: 具体代码可以根据vue element admin源码进行更改,下面是页面代码 <el-form ref="loginForm" :model="log ...
- base32php,ThinkPHP6.0使用extends Base方式处理后台登录逻辑
无论是后台管理系统还是用户端,登录场景是必备的.那么掌握高效的写法是非常有利于后期的维护的.使用ThinkPHP6.0可以使用两种非常高效的写法. 一种是使用功能类继承的方式,一种是使用中间件拦截来实 ...
- 聊聊小程序的登录逻辑
聊聊小程序的登录逻辑 一直聊的都是客户运营方面的话题,毕竟斗金客户运营系统小程序产品是依靠技术实现的,今天来聊聊大家都能感知到的小程序登录问题吧,大家可能都碰到过很多小程序刚打开就要求授权获取信息之类 ...
- Vue Element Admin 使用mock模块模拟数据
Mock 数据是前端开发过程中必不可少的一环,是分离前后端开发的关键链路.通过预先跟服务器端约定好的接口,模拟请求数据甚至逻辑,能够让前端开发更加独立自主,不会被服务端的开发所阻塞. vue-elem ...
- ios 仿电脑qq登录界面_1、IOS开发--iPad之仿制QQ空间(登录界面搭建+登录逻辑实现)...
开始搭建登录界面 登录界面效果图: 步骤开始: 设置辅助窗口的位置在下方 快捷键option,然后拖拽复制之后: 这里就直接省去了将背景颜色改为经典黑了. 到这里QQ空间的登录界面搭建完毕. 下面进行 ...
- 12、ABPZero系列教程之拼多多卖家工具 拼团提醒功能登录拼多多实现
上篇文章已经完成了整个拼多多拼团提醒功能,本篇继续完成拼多多帐号登录,拼多多帐号登录的目的是为了获取拼团商品的SKU和订单号,便于商家备货. 以下是拼多多官方的后台登录,要实现的功能并不是直接在这里登 ...
最新文章
- 二分查找递归与非递归方式的实现
- 如何更加简单的理解JS中的原型原型链概念
- 堆栈和堆得区别与垃圾回收
- 电竞+区块链,玩家的4大入局方式
- redirect_uri 域名与后配置不一致是什么意思_网站域名怎么购买?多少钱?
- easyUI导入导出
- Java WebService使用简单教程
- 不刷新改变/更换URL: pushState + Ajax
- Kubernetes 之 MySQL 持久存储和故障转移(十一)
- 【优化预测】基于matlab差分进化改进灰狼算法优化SVR预测【含Matlab源码 1283期】
- C# BackgroundWorker用法详解
- LS1012ARDB - How to reflash u-boot / RCW via built in Kinetis CMSIS-DAP
- 【转】Steam 开发者收入计算
- S1 data forwarding测试方法
- presto日期转换及计算
- Python(十三)IO编程
- adobe清理工具_Adobe终于通过其新的渐变工具实现了这一点-UX评论
- [附源码]计算机毕业设计JAVA汽车租赁系统
- 【STM32】SPI的基本原理、库函数(SPI一般步骤)
- vue解决-4048报错
热门文章
- 如何实现点击微信内置浏览器返回按钮,返回指定页面,或者原地刷新
- java代码杨辉三角_用java实现杨辉三角的示例代码
- nginx输出日志_ingressnginx持久化日志
- jeecgboot 弹出modal刷新主窗体_保利天汇|自然的温度,刷新园林美学天际/辽宁房产特刊...
- mysql explain 索引_MySql中Explain详解与索引最佳实践
- curl -O 下载文件
- IO概述、异常、File文件类_DAY19
- 当我们在聊监控,我们在聊什么?
- 2016.9.24 の 測試
- windows API 开发飞机订票系统 图形化界面 (二)