vue-element-admin改造顶部一级导航,侧边二级导航+权限路由

  • 前言
  • 步骤
    • src/permission.js
    • src/store/modules/permission.js
    • src/store/modules/user.js
    • src/store/getters.js
    • src/layout/components/Topbar.vue

前言

在作者的基础上添加权限路由,原型地址
方法和在vue-admin-template模板上加权限路由差不多。
涉及到的几个文件
src/permission.js
src/store/modules/permission.js
src/store/modules/user.js
src/store/getters.js
src/layout/components/Topbar.vue

步骤

src/permission.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 Configurationconst whiteList = ['/login'] // no redirect whitelistrouter.beforeEach(async(to, from, next) => {// start progress barNProgress.start()// set page titledocument.title = getPageTitle(to.meta.title)// determine whether the user has logged inconst hasToken = getToken()if (hasToken) {if (to.path === '/login') {// if is logged in, redirect to the home pagenext({ path: '/' })NProgress.done()} else {// determine whether the user has obtained his permission roles through getInfoconst hasRoles = store.getters.roles && store.getters.roles.length > 0if (hasRoles) {next()} else {try {// get user info// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']const { roles } = await store.dispatch('user/getInfo')// generate accessible routes map based on rolesconst accessRoutes = await store.dispatch('permission/generateRoutes', roles)// dynamically add accessible routesrouter.addRoutes(accessRoutes)// hack method to ensure that addRoutes is complete// set the replace: true, so the navigation will not leave a history recordnext({ ...to, replace: true })} catch (error) {// remove token and go to login page to re-loginawait 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) {// in the free login whitelist, go directlynext()} else {// other pages that do not have permission to access are redirected to the login page.next(`/login?redirect=${to.path}`)NProgress.done()}}
})router.afterEach(() => {// finish progress barNProgress.done()
})

src/store/modules/permission.js

import { asyncRoutes, constantRoutes } from '@/router'/*** Use meta.role to determine if the current user has permission* @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}
}/*** Filter asynchronous routing tables by recursion* @param routes asyncRoutes* @param roles*/
export function filterAsyncRoutes(routes, roles) {const res = []routes.forEach(route => {const tmp = { ...route }if (hasPermission(roles, tmp)) {if (tmp.children) {tmp.children = filterAsyncRoutes(tmp.children, roles)}res.push(tmp)}})return res
}const state = {routes: [],addRoutes: [],currentRoutes: {}
}const mutations = {SET_ROUTES: (state, routes) => {state.addRoutes = routesstate.routes = constantRoutes.concat(routes)},SET_CURRENT_ROUTES: (state, routes) => {state.currentRoutes = routes}
}const actions = {generateRoutes({ commit }, roles) {return new Promise(resolve => {let accessedRoutesif (roles.includes('admin')) {accessedRoutes = asyncRoutes || []} else {accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)}commit('SET_ROUTES', accessedRoutes)resolve(accessedRoutes)})}
}export default {namespaced: true,state,mutations,actions
}

src/store/modules/user.js

import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { resetRouter } from '@/router'const getDefaultState = () => {return {token: getToken(),name: '',avatar: '',roles: []}
}const state = getDefaultState()const mutations = {RESET_STATE: (state) => {Object.assign(state, getDefaultState())},SET_TOKEN: (state, token) => {state.token = token},SET_NAME: (state, name) => {state.name = name},SET_AVATAR: (state, avatar) => {state.avatar = avatar},SET_ROLES: (state, roles) => {state.roles = roles}
}const actions = {// user loginlogin({ commit }, userInfo) {const { username, password } = userInforeturn new Promise((resolve, reject) => {login({ username: username.trim(), password: password }).then(response => {const { data } = responsecommit('SET_TOKEN', data.token)setToken(data.token)resolve()}).catch(error => {reject(error)})})},// get user infogetInfo({ commit, state }) {return new Promise((resolve, reject) => {getInfo(state.token).then(response => {const { data } = responseif (!data) {reject('Verification failed, please Login again.')}const { roles, name, avatar } = data// roles must be a non-empty arrayif (!roles || roles.length <= 0) {reject('getInfo: roles must be a non-null array!')}commit('SET_ROLES', roles)commit('SET_NAME', name)commit('SET_AVATAR', avatar)resolve(data)}).catch(error => {reject(error)})})},// user logoutlogout({ commit, state }) {return new Promise((resolve, reject) => {logout(state.token).then(() => {removeToken() // must remove  token  firstresetRouter()commit('RESET_STATE')resolve()}).catch(error => {reject(error)})})},// remove tokenresetToken({ commit }) {return new Promise(resolve => {removeToken() // must remove  token  firstcommit('RESET_STATE')resolve()})}
}export default {namespaced: true,state,mutations,actions
}

src/store/getters.js

const getters = {sidebar: state => state.app.sidebar,device: state => state.app.device,token: state => state.user.token,avatar: state => state.user.avatar,name: state => state.user.name,roles: state => state.user.roles,permission_routes: state => state.permission.routes
}
export default getters

src/layout/components/Topbar.vue

主要是把v-for="item in routes"改成v-for="item in permission_routes",并添加...mapGetters(["avatar", "permission_routes"]),而不是在Siderbar/index.vue中修改。

<template><div class="top-nav"><div class="log">带一级导航的后台管理系统</div><el-menu:active-text-color="variables.menuActiveText":default-active="activeMenu"mode="horizontal"@select="handleSelect"><div v-for="item in permission_routes" :key="item.path" class="nav-item"><app-link :to="resolvePath(item)"><el-menu-item v-if="!item.hidden" :index="item.path">{{item.meta ? item.meta.title : item.children[0].meta.title}}</el-menu-item></app-link></div></el-menu><div class="right-menu"><el-dropdown class="avatar-container" trigger="click"><div class="avatar-wrapper"><img :src="avatar + '?imageView2/1/w/80/h/80'" class="user-avatar" /><i class="el-icon-caret-bottom" /></div><el-dropdown-menu slot="dropdown" class="user-dropdown"><router-link to="/"><el-dropdown-item>Home</el-dropdown-item></router-link><ahref="https://github.com/PanJiaChen/vue-admin-template/"target="_blank"><el-dropdown-item>Github</el-dropdown-item></a><ahref="https://panjiachen.github.io/vue-element-admin-site/#/"target="_blank"><el-dropdown-item>Docs</el-dropdown-item></a><el-dropdown-item divided @click.native="logout"><span style="display: block">Log Out</span></el-dropdown-item></el-dropdown-menu></el-dropdown></div></div>
</template><script>
import { mapGetters } from "vuex";
import AppLink from "./Sidebar/Link";
import { constantRoutes } from "@/router";
import variables from "@/styles/variables.scss";
import { isExternal } from "@/utils/validate";export default {name: "Topbar",components: {AppLink,},data() {return {routes: constantRoutes,};},computed: {activeMenu() {const route = this.$route;const { meta, path } = route;// if set path, the sidebar will highlight the path you setif (meta.activeMenu) {return meta.activeMenu;}// 如果是首页,首页高亮if (path === "/dashboard") {return "/";}// 如果不是首页,高亮一级菜单const activeMenu = "/" + path.split("/")[1];return activeMenu;},variables() {return variables;},sidebar() {return this.$store.state.app.sidebar;},...mapGetters(["avatar", "permission_routes"]),},mounted() {this.initCurrentRoutes();},methods: {// 通过当前路径找到二级菜单对应项,存到store,用来渲染左侧菜单initCurrentRoutes() {const { path } = this.$route;let route = this.routes.find((item) => item.path === "/" + path.split("/")[1]);// 如果找不到这个路由,说明是首页if (!route) {route = this.routes.find((item) => item.path === "/");}this.$store.commit("permission/SET_CURRENT_ROUTES", route);this.setSidebarHide(route);},// 判断该路由是否只有一个子项或者没有子项,如果是,则在一级菜单添加跳转路由isOnlyOneChild(item) {if (item.children && item.children.length === 1) {return true;}return false;},resolvePath(item) {// 如果是个完成的url直接返回if (isExternal(item.path)) {return item.path;}// 如果是首页,就返回重定向路由if (item.path === "/") {const path = item.redirect;return path;}// 如果有子项,默认跳转第一个子项路由let path = "";/*** item 路由子项* parent 路由父项*/const getDefaultPath = (item, parent) => {// 如果path是个外部链接(不建议),直接返回链接,存在个问题:如果是外部链接点击跳转后当前页内容还是上一个路由内容if (isExternal(item.path)) {path = item.path;return;}// 第一次需要父项路由拼接,所以只是第一个传parentif (parent) {path += parent.path + "/" + item.path;} else {path += "/" + item.path;}// 如果还有子项,继续递归if (item.children) {getDefaultPath(item.children[0]);}};if (item.children) {getDefaultPath(item.children[0], item);return path;}return item.path;},handleSelect(key, keyPath) {// 把选中路由的子路由保存storeconst route = this.routes.find((item) => item.path === key);this.$store.commit("permission/SET_CURRENT_ROUTES", route);this.setSidebarHide(route);},// 设置侧边栏的显示和隐藏setSidebarHide(route) {if (!route.children || route.children.length === 1) {this.$store.dispatch("app/toggleSideBarHide", true);} else {this.$store.dispatch("app/toggleSideBarHide", false);}},async logout() {await this.$store.dispatch("user/logout");this.$router.push(`/login?redirect=${this.$route.fullPath}`);},},
};
</script>

最后修改router/index.js
静态路由放在constantRoutes中,需要做权限判断的动态路由放在asyncRoutes中,并添加roles。

vue-element-admin改造顶部一级导航,侧边二级导航+权限路由相关推荐

  1. Vue Element Admin 使用mock模块模拟数据

    Mock 数据是前端开发过程中必不可少的一环,是分离前后端开发的关键链路.通过预先跟服务器端约定好的接口,模拟请求数据甚至逻辑,能够让前端开发更加独立自主,不会被服务端的开发所阻塞. vue-elem ...

  2. vue+element+admin(初始化项目)

    2022.10.17我接触到了vue+element+admin的使用,首先要安装node.jshttps://nodejs.org/zh-cn/download/.和githttps://git-s ...

  3. vue element admin登录方式切换(密码登录或短信登录)

    显示结果: 具体代码可以根据vue element admin源码进行更改,下面是页面代码 <el-form ref="loginForm" :model="log ...

  4. vue-element-admin改造顶部一级导航,侧边二级导航

    本项目是基于vue-element-admin的基础模板vue-admin-template进行改造的,因为实际项目很多会用到顶部导航菜单和侧边导航相结合的情况,为了满足这种需求做了改造. 先上效果图 ...

  5. 后端使用SpringBoot和Jwt工具与Redis数据库+前端Vue Element Admin实现用户携带token的登录功能案例

    登录功能描述: 前端输入对应的用户信息 ,在用户输入邮箱后 点击发送按钮给邮箱发送验证码,拿取到验证填完之后,点击登录按钮给后端发送请求 ,后端接收到请求之后 ,第一步校验验证码,第二步校验用户名和密 ...

  6. Vue Element Admin 添加侧边栏以及他的页面

    1. 在 /src/views/ 下添加需要的页面 2. 配置路由器 router 中的路由表 routes,分为 constantRoutes 和 asyncRoutes. 将路由的配置信息添加进路 ...

  7. Vue Element Admin 用mock模块模拟数据

    步骤简单 一  在 src/api/charts 中添加接口 , 方法名为 getindexMock  import request from '@/utils/request'export func ...

  8. vue element admin中发送请求和设置loading效果

    需求:在表格数据加载完成前进入loading显示数据正在加载,数据加载完成后取消loading效果,axios的超时处理和异常的处理之后进行取消loading效果. 小编接下来就根据这个这个需求进行分 ...

  9. 以太网速率怎么手动设置_OPENWRT-KOOLSHARE软路由,一级/单臂/二级/旁软路由设置单臂路由联网教程...

    [此文原创]此文基于单口软路由讨论 一级/单臂路由 LAN:IPV4设置除192.168.1.1之外和你局域网不冲突的地址,关闭桥接接口,物理设置eth0 WAN:协议改成PPPOE,物理设置eth0 ...

最新文章

  1. [sqlserver脚本]查看指定SQL语句生成了哪些执行计划
  2. 【选摘】为什么说SAP中没有在制品的盘点
  3. 前端逼死强迫症系列之javascript续集
  4. Nacos配置管理-微服务配置拉取
  5. <MySQL>何时使用普通索引,何时使用唯一索引
  6. android自定义控件几种,Android 自定义View一个控件搞定多种水波纹涟漪扩散效果 - CSDN博客...
  7. 数据与AI如何提升IT运维价值?锐捷发布乐享智能运维管理平台
  8. mysql mybatis 工具类_我肝了一个星期,为你们整理出了mybatis程序配置教程
  9. 智能行业热点速览(2019.7.15)
  10. 小米9来袭 雷军微博疯狂暗示:有望MWC亮相?
  11. 应用实例_兴达奇智能燃烧控制器BMU460DP现场应用实例图
  12. 关于URL编码(转载)
  13. 笔试错题--(字符串常量池和JVM运行时数据区)
  14. 小程序如何复用公众号资质快速认证
  15. 基于两输出一输入BP神经网络的传感器检测数据融合(附带MATLAB代码)
  16. LeetCode,无它,唯手熟尔(四)
  17. GetAsyncKeyState()用法
  18. 白光干涉衍射实验的计算机仿真,白光干涉_衍射实验的计算机仿真_蓝海江
  19. neo4j报错1:因CREATE和MERGE报错
  20. public、private、protected的区别

热门文章

  1. docker/Dockerfile/docker compose
  2. 中国医科大学2021年9月《急危重症护理学》作业考核试题
  3. css调整标签内背景图片的大小和位置
  4. 华硕电脑桌面没有计算机图标 怎么弄出来,电脑桌面图标不见了怎么恢复 电脑桌面图标怎么随意设置...
  5. H5打造属于自己的视频播放器(JS篇1)
  6. python3 23.keras使用交叉熵代价函数进行MNIST数据集简单分类 学习笔记
  7. 不用自学APP开发:零基础也能制作APP软件,兼容iOS
  8. 01 Redis安装、配置详解、数据备份与恢复
  9. STM32+ws2812灯条,点灯升级版
  10. 华理2019信号与系统考研模拟试题(含数字信号处理)