新增路由 vue html,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'exportfunctionlogin(data) {returnrequest({

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 constconstantRoutes=[

{

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 = () => newRouter({//mode: 'history', // 需要服务支持

scrollBehavior: () => ({ y: 0}),

routes: constantRoutes

})var router =createRouter()//重置路由//Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465

export functionresetRouter() {

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}

];

exportdefault 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';functionhasPermission(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)) {returnchild

}return false;

});returnv

}else{returnv

}

}return false;

});

commit('SET_ROUTERS', accessedRouters);

resolve();

})

}

}

};

exportdefault permission;

GenerateRoutes方法办了一件事,就是把动态路由配置里符合用户权限的配置筛选出来,组成一个数组,然后,和固定路由合并到了一起,存到了vuex中,

然后调用了这两句代码:

router.addRoutes(store.getters.addRouters); //动态添加可访问路由表

router.options.routes=store.getters.routers;

router.addRoutes()方法是,动态添加路由配置,参数是符合路由配置的数组,

然后将路由元信息,变成合并后的路由元信息,因为渲染侧边栏需要用到,

这两句代码,顺序不能变,缺一不可,缺了addRoutes,点击侧边栏的动态路由会无反应,缺了options,侧边栏显示不出来动态添加的路由!!!!

以上就是element-admin的动态路由了,睡觉。。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值