900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > vue + elementui 实现动态侧边导航栏

vue + elementui 实现动态侧边导航栏

时间:2023-09-04 15:38:47

相关推荐

vue + elementui 实现动态侧边导航栏

vue + elementui 实现动态侧边导航栏

引言router 文件夹创建 layout 文件夹components 创建 SubMenu 文件夹封装动态侧边栏vuex 中根据权限动态获取路由获取路由的时机

引言

后台管理系统中,前端往往需要根据用户的权限动态添加路由,以此来展现用户所能访问的页面,基于这个要求,根据网上的资料封装动态的侧边导航栏

前端传的权限参数和后端返回的权限都为数组,里面包含的是字符串

router 文件夹

// index.tsimport Vue from 'vue';import VueRouter from 'vue-router';import Login from '@/views/login/index.vue';import Layout from '@/layout/index.vue';Vue.use(VueRouter);/*** hidden 表示是否需要在侧边导航栏出现 ,true表示不需要* isFirst 表示是否只有一级权限,只出现在只有一个子集,没有其他孙子集* 当权限拥有多个子集或者孙子集,一级权限需要加上 meta* 二级权限拥有子集,也必须有 meta*/// 基础路由export const constantRoutes = [{path: '/redirect',component: Layout,hidden: true,children: [{path: '/redirect/:path(.*)',component: () => import('@/views/redirect/index.vue')}]},{path: '/',redirect: '/dashboard',hidden: true},{path: '/login',name: 'Login',component: Login,hidden: true},{path: '/dashboard',component: Layout,redirect: '/dashboard/index',isFirst: true,children: [{path: 'index',name: 'Dashboard',component: () => import('@/views/dashboard/index.vue'),meta: {title: '首页',icon: 'el-icon-location'}}]}];// 动态路由export const asyncRoutes = [{path: '/form',component: Layout,redirect: '/form/index',isFirst: true,children: [{path: 'index',name: 'Form',component: () => import('@/views/form/index.vue'),meta: {title: '表单',role: 'form',icon: 'el-icon-location'}}]},{path: '/editor',component: Layout,redirect: '/editor/index',meta: {role: 'editors',title: '总富文本',icon: 'el-icon-location'},children: [{path: 'index',name: 'Editor',component: () => import('@/views/editor/index.vue'),meta: {title: '富文本',role: 'editor',icon: 'el-icon-location'}},{path: 'two',name: 'Two',redirect: '/editor/two/three',component: () => import('@/views/editor/two.vue'),meta: {title: '二级导航',role: 'two',icon: 'el-icon-location'},children: [{path: 'three',name: 'Three',component: () => import('@/views/editor/three.vue'),meta: {title: '三级导航',role: 'three',icon: 'el-icon-location'}},{path: 'four',name: 'Four',component: () => import('@/views/editor/four.vue'),meta: {title: '三级导航2',role: 'four',icon: 'el-icon-location'}}]}]},{path: '/tree',component: Layout,redirect: '/tree/index',isFirst: true,children: [{path: 'index',name: 'Tree',component: () => import('@/views/tree/index.vue'),meta: {title: '树状图',role: 'tree',icon: 'el-icon-location'}}]},{path: '/excel',component: Layout,redirect: '/excel/index',isFirst: true,children: [{path: 'index',name: 'Excel',component: () => import('@/views/excel/index.vue'),meta: {title: '导入导出',role: 'excel',icon: 'el-icon-location'}}]}];// 出错跳转的路由export const error = [// 404{path: '/404',component: () => import('@/views/error/index.vue'),hidden: true},{path: '*',redirect: '/404',hidden: true}];const createRouter = () =>new VueRouter({scrollBehavior: () => ({x: 0,y: 0}),routes: constantRoutes});const router = createRouter();// 刷新路由export function resetRouter () {const newRouter = createRouter();(router as any).matcher = (newRouter as any).matcher;}export default router;

创建 layout 文件夹

<!-- index.vue 用于定义页面的基础布局 --><template><div class="layout"><el-container><!-- 头部 --><el-header><div class="header-content"><p class="header-tit">运营后台</p><div class="user-info"><el-dropdown placement="bottom" @command="handleCommand"><div class="el-dropdown-link"><img src="" alt="" /><p class="header-username">小红</p><i class="el-icon-arrow-down el-icon--right"></i></div><el-dropdown-menu slot="dropdown"><el-dropdown-item command="info">个人信息</el-dropdown-item><el-dropdown-item command="logout">退出登录</el-dropdown-item></el-dropdown-menu></el-dropdown></div></div></el-header><el-container :class="{ hideSidebar: isCollapse }"><!-- 侧边导航栏 --><el-aside class="sidebar-container"><el-scrollbar><el-menu:collapse="isCollapse":default-active="$router.currentRoute.path":collapse-transition="false"background-color="#eee"text-color="#666"active-text-color="#0099ff"@select="handleSelect"v-if="permissionRoutes"><template v-for="item in permissionRoutes"><el-menu-itemv-if="!item.hidden && item.children.length === 1 && item.isFirst":index="item.redirect":key="item.path"><i :class="item.children[0].meta.icon"></i><span slot="title">{{ item.children[0].meta.title }}</span></el-menu-item><sub-menuv-if="!item.hidden && !item.isFirst":item="item":key="item.path":basePath="item.path"></sub-menu></template></el-menu></el-scrollbar></el-aside><!-- 主体内容 --><el-main><router-view /></el-main></el-container></el-container></div></template><script lang="ts">import Vue from 'vue';import {mapGetters } from 'vuex';import SubMenu from '@/components/SubMenu/index.vue';import {resetRouter } from '@/router';export default Vue.extend({computed: {// 路由...mapGetters(['permissionRoutes'])},methods: {// 页面跳转handleSelect (index: string) {if (this.$router.currentRoute.path === index) {return;}this.$router.push(index);},// 下拉框选择handleCommand (command: string) {if (command === 'logout') {localStorage.clear();resetRouter();this.$router.push({name: 'Login' });}}},components: {SubMenu}});</script><style lang="less" scoped>.layout {width: 100%;height: 100vh;.header-content {height: 100%;display: flex;justify-content: space-between;align-items: center;color: #fff;.header-tit {font-size: 18px;font-weight: bold;}.user-info {display: flex;align-items: center;.el-dropdown-link {display: flex;align-items: center;img {width: 35px;height: 35px;border-radius: 50%;margin-right: 10px;}.header-username {font-size: 16px;color: #fff;}}}}}/deep/.el-header {background-color: #333;}/deep/.el-main {background-color: #f2f2f2;}/deep/.el-scrollbar {height: 100%;background-color: #eee;}// 折叠展开动画.sidebar-container {transition: width 0.28s;width: 200px !important;height: 100%;overflow: hidden;.el-menu {border: none;height: 100%;width: 100% !important;}}.hideSidebar {.sidebar-container {width: 60px !important;}}</style>

components 创建 SubMenu 文件夹封装动态侧边栏

<!-- index.vue--><template functional><el-submenu :index="props.item.path" popper-append-to-body><template slot="title"><i :class="props.item.meta.icon"></i><span>{{ props.item.meta.title }}</span></template><template v-for="item in props.item.children"><el-menu-item:index="props.basePath + '/' + item.path":key="item.path"v-if="!item.children"><template slot="title"><i :class="item.meta.icon"></i><span>{{ item.meta.title }}</span></template></el-menu-item><sub-menuv-else:item="item":key="item.path":basePath="props.basePath + '/' + item.path"></sub-menu></template></el-submenu></template><script lang="ts">import Vue from 'vue';export default Vue.extend({name: 'Submenu',props: {item: {type: Object,required: true},basePath: {type: String,required: true}}});</script><style lang="less" scoped></style>

vuex 中根据权限动态获取路由

// modules/permission.tsimport {getUserPermission } from '@/utils/localStorage';import {constantRoutes, asyncRoutes, error } from '@/router';// 判断是否有此权限路由function hasPermissionRouter (roles: any, route: any) {if (route.children && route.children.length === 1 && !route.meta) {return roles.some((role: any) => route.children[0].meta.role === role);} else if (route.meta && route.meta.role) {return roles.some((role: any) => route.meta.role === role);} else {return false;}}// 获取用户路由export function filterAsyncRoutes (router: any[], roles: any[]) {const resArr: any[] = [];router.forEach((route) => {if (hasPermissionRouter(roles, route)) {if (route.children && (route.children.length > 1 || route.meta)) {route.children = filterAsyncRoutes(route.children, roles);}resArr.push(route);}});return resArr;}const state = {// 所有路由(不包含 error 路由)routes: [],// 动态添加的路由addRoutes: []};const mutations = {SET_ROUTES: (state: any, routes: any) => {state.addRoutes = routes;state.routes = constantRoutes.concat(routes);}};const actions = {generateRoutes ({commit }: {commit: any }) {return new Promise((resolve) => {const accessedRoutes = filterAsyncRoutes(asyncRoutes,JSON.parse(getUserPermission()));commit('SET_ROUTES', accessedRoutes);// error 路由需要放在最后,不然会出现所有路径都跳转到 404 页面的情况resolve(accessedRoutes.concat(error));});}};export default {namespaced: true,state,mutations,actions};

// getters.tsconst getters = {// 用户路由permissionRoutes: (state: any) => state.permission.routes};export default getters;

// index.tsimport Vue from 'vue';import Vuex from 'vuex';import getters from './getters';Vue.use(Vuex);const modulesFiles = require.context('./modules', true, /\.ts$/);const modules = modulesFiles.keys().reduce((modules, modulePath) => {// set './permission.ts' => 'permission'const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1');const value = modulesFiles(modulePath);(modules as any)[moduleName] = value.default;return modules;}, {});export default new Vuex.Store({modules,getters});

获取路由的时机

import router, {resetRouter } from './router';import store from './store';import {getUserPermission, setUserPermission } from '@/utils/localStorage';// 判断是否初次或者刷新页面 0表示初次let isRequest = 0;router.beforeEach(async (to, from, next) => {async function init () {// 调用方法获取路由const accessRoutes = await store.dispatch('permission/generateRoutes');accessRoutes.forEach((route: any) => {router.addRoute(route);});isRequest = 1;}// const hasToken = getToken();const userPermission = JSON.parse(getUserPermission());// 判断条件根据项目更改if (userPermission.length) {if (to.path === '/login') {next({path: '/' });}if (isRequest) {next();} else {// 刷新页面,在这里需要重新获取并设置权限const userPermission = ['form','editor','editors','two','three','tree','four'];setUserPermission(JSON.stringify(userPermission));await init();next({...(to as any), replace: true });}} else {localStorage.clear();isRequest = 0;if (to.path === '/login') {next();} else {resetRouter();next({path: '/login'});}}});

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。