读vue-element-admin源码二三事(一)
因为本人是前端纯菜鸟,除了上周大概看了vue.js较简单的部分以及简单的ajax和js基础框架什么接触的少,其他没接触过,以下没接触过的框架用单行代码表示,如123文章目录基础登录主页基础登录路由看着路由带#还是很不舒适,于是router/index.js内的export default new Router({mode: 'history', // require serv...
·
因为本人是前端纯菜鸟,除了上周大概看了vue.js较简单的部分以及简单的ajax和js基础框架什么接触的少,其他没接触过,以下没接触过的框架用单行代码表示,如123
基础
登录
- 路由
看着路由带#还是很不舒适,于是router/index.js内的
export default new Router({
mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
})
mode:histroy部分放开去#号
- URL过滤
main.js内导入了permission.js,代码如下:
router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
if (getToken()) { // determine if there has token
/* has token*/
if (to.path === '/login') {
next({ path: '/' })
NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
}).catch((err) => {
store.dispatch('FedLogOut').then(() => {
Message.error(err || 'Verification failed, please login again')
next({ path: '/' })
})
})
} else {
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
if (hasPermission(store.getters.roles, to.meta.roles)) {
next()
} else {
next({ path: '/401', replace: true, query: { noGoBack: true }})
}
// 可删 ↑
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
next()
} else {
next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
}
}
})
此处用到框架:NProgress.js
大概看了一下,是个进度条。
最外层伪代码:
如果(有token【已登录】){
。。。
}否则{
如果(当前跳转地址在白名单【此地址不需要登录允许匿名访问】){
直接进入
}否则{
回登录页
}
}
由此拦截未登录的用户到登录页
- 角色管理
继续看beforeEach部分,会发现登录后,有一个拉去用户数据,然后生成路由的特殊部分,用了vuex的store
,内部根据asyncRouterMap和当前角色(目前有admin和editor[editor需过滤])进行路由筛选,实际是检查路由的meta->roles字段是否包含当前角色,包含就放入路由中。主要通过下列两段代码完成:
src/store/modules/permission.js
/**
* 通过meta.role判断是否与当前用户权限匹配
* @param roles
* @param route
*/
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
/**
* 递归过滤异步路由表,返回符合用户角色权限的路由表
* @param routes asyncRouterMap
* @param roles
*/
function filterAsyncRouter(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRouter(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
- 多语言
用到框架:vue-i18n
具体用法见src/components/LangSelect/index.vue
<template>
<el-dropdown trigger="click" class="international" @command="handleSetLanguage">
<div>
<svg-icon class-name="international-icon" icon-class="language" />
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :disabled="language==='zh'" command="zh">中文</el-dropdown-item>
<el-dropdown-item :disabled="language==='en'" command="en">English</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
computed: {
language() {
return this.$store.getters.language
}
},
methods: {
handleSetLanguage(lang) {
this.$i18n.locale = lang
this.$store.dispatch('setLanguage', lang)
this.$message({
message: 'Switch Language Success',
type: 'success'
})
}
}
}
</script>
主页
代码:
{
path: '',
component: Layout,
redirect: 'dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
name: 'Dashboard',
meta: { title: 'dashboard', icon: 'dashboard', noCache: true }
}
]
},
看路由是Layout里面嵌套了一个<router-view/>
里面放了主面板,看代码是这样:
<template>
<div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<sidebar class="sidebar-container"/>
<div class="main-container">
<navbar/>
<tags-view/>
<app-main/>
</div>
</div>
</template>
就是侧边栏+主栏,主栏包括导航栏,标签栏和内容。
- 侧边栏
<template>
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:show-timeout="200"
:default-active="$route.path"
:collapse="isCollapse"
mode="vertical"
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
>
<sidebar-item v-for="route in permission_routers" :key="route.name" :item="route" :base-path="route.path"/>
</el-menu>
</el-scrollbar>
</template>
这里如果没有看路由过滤是会有点费解的。通过路由过滤动态设置路由,然后再把路由传到这里,然后看sidebar-item内部:
<template>
<div v-if="!item.hidden&&item.children" class="menu-wrapper">
<!--单根直接链接,多个下拉列表-->
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<a :href="onlyOneChild.path" target="_blank" @click="clickLink(onlyOneChild.path,$event)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
<item v-if="onlyOneChild.meta" :icon="onlyOneChild.meta.icon||item.meta.icon" :title="generateTitle(onlyOneChild.meta.title)" />
</el-menu-item>
</a>
</template>
<el-submenu v-else :index="item.name||item.path">
<template slot="title">
<item v-if="item.meta" :icon="item.meta.icon" :title="generateTitle(item.meta.title)" />
</template>
<template v-for="child in item.children" v-if="!child.hidden">
<sidebar-item
v-if="child.children&&child.children.length>0"
:is-nest="true"
:item="child"
:key="child.path"
:base-path="resolvePath(child.path)"
class="nest-menu" />
<a v-else :href="child.path" :key="child.name" target="_blank" @click="clickLink(child.path,$event)">
<el-menu-item :index="resolvePath(child.path)">
<item v-if="child.meta" :icon="child.meta.icon" :title="generateTitle(child.meta.title)" />
</el-menu-item>
</a>
</template>
</el-submenu>
</div>
</template>
其实不是很复杂,就是如果当前根路由没有hidden,并且有子路由,分两种情况处理:
1.单个子路由或除了一个子路由其他全部隐藏
例如:
{
path: '',
component: Layout,
redirect: 'dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
name: 'Dashboard',
meta: { title: 'dashboard', icon: 'dashboard', noCache: true }
}
]
}
就是首页,那么点击标题直接进行链接。
2.多个子路由打开下拉列表,下拉列表再进行链接
例如:
{
path: '/permission',
component: Layout,
redirect: '/permission/index',
alwaysShow: true, // will always show the root menu
meta: {
title: 'permission',
icon: 'lock',
roles: ['admin', 'editor'] // you can set roles in root nav
},
children: [
{
path: 'page',
component: () => import('@/views/permission/page'),
name: 'PagePermission',
meta: {
title: 'pagePermission',
roles: ['admin'] // or you can only set roles in sub nav
}
},
{
path: 'directive',
component: () => import('@/views/permission/directive'),
name: 'DirectivePermission',
meta: {
title: 'directivePermission'
// if do not set roles, means: this page does not require permission
}
}
]
}
今天到这里了,剩下时间打算看看上述的几个框架vuex store
,element ui
和vue-i18n
,还不太会用。
更多推荐
已为社区贡献3条内容
所有评论(0)