标签介绍:el-menu为导航菜单组件,el-menu-item表示无子菜单的菜单项,el-submenu表示有子菜单的菜单项。
一、使用NavMenu做为导航菜单,实现的不好会出现点击菜单跳转到新页面的情况。如果想要实现本页跳转,可以参考以下步骤:
1、菜单首页的路由需要做为其他菜单页的父级路由。如菜单页为index.vue,现有用户页user.vue,这个user和index的文件目录没有任何要求,但user的路由需要是index的子路由,如index路由为/index,user路由为/user,是不可以的,此时user的路由需要是/index/...,如下是我的路由实例:
{
path: '/menu',
name: 'menu',
hidden:true,
component: () => import('@/views/menu/index'),
children: [
//给菜单页一个默认的菜单显示
{
path: '/user',
redirect: 'user'
},
{
path: '/menu/user',
name: 'user',
component: () => import('@/views/menu/user')
},
{
path: '/menu/role',
name: 'role',
component: () => import('@/views/menu/role')
},
]
}
2、el-menu菜单组件标签加上如下配置: :default-active="$route.path"和router,开启路由;
3、需要跳转的菜单el-menu-item标签上index使用路由表示,如
用户管理
4、菜单页使用
二、固定菜单实例:
1、效果:访问系统判断是否已登录,未登录则跳转到登录页,已登录则进入中间页(额外插入的功能,测试navbar做导航),从中间页可以进入首页。
(1)登录页:
(2)登录成功跳转到中间页:
(3)点击其他菜单试试:
(4)点击第一个菜单页里面的按钮“点击跳转”,这个才是我插入navbar测试页之前的主页,这里的菜单权限是从后台配置的:
2、代码:
(1)route路由:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '../views/layout/Layout'
export const constantRouterMap = [
{ path: '/404', component: () => import('@/views/404'), hidden: true },
{ path: '/login', component: () => import('@/views/login/index'), hidden: true },
{
path: '/midtest',
name: 'midtest',
hidden:true,
component: () => import('@/views/midtest/index'),
children: [
{
path: '/midtest',
redirect: 'midtest1'
},
{
path: '/midtest/midtest1',
name: 'midtest1',
component: () => import('@/views/midtest/midtest1')
},
{
path: 'midtest2',
name: 'midtest2',
component: () => import('@/views/midtest/midtest2')
},
{
path: 'midtest3',
name: 'midtest3',
component: () => import('@/views/midtest/midtest3')
},
{
path: 'midtest41',
name: 'midtest41',
component: () => import('@/views/midtest/midtest4/midtest41')
},
{
path: 'midtest42',
name: 'midtest42',
component: () => import('@/views/midtest/midtest4/midtest42')
},
{
path: 'midtest51',
name: 'midtest51',
component: () => import('@/views/midtest/midtest5/midtest51')
},
{
path: 'midtest521',
name: 'midtest521',
component: () => import('@/views/midtest/midtest5/midtest521')
},
{
path: 'midtest522',
name: 'midtest522',
component: () => import('@/views/midtest/midtest5/midtest522')
}
]
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
name: '首页',
icon: '首页',
hidden: true,
children: [{
path: '/dashboard',
component: () => import('@/views/dashboard/index')
}]
}
]
/**
* hidden: true if `hidden:true` will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu, whatever its child routes length
* if not set alwaysShow, only more than one route under the children
* it will becomes nested mode, otherwise not show the root menu
* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
* name:'router-name' the name is used by (must set!!!)
* meta : {
title: 'title' the name show in submenu and breadcrumb (recommend set)
icon: 'svg-name' the icon show in the sidebar,
}
**/
export const asyncRouterMap = [
// { path: '/login', component: () => import('@/views/login/index'), hidden: true },
{
path: '/roleManage',
redirct: '/roleManage/index',
name: 'roleManage',
component: Layout,
meta: { title: '角色管理', authority: ['role_manage'] },
noDropdown: true,
children: [
{
path: 'index',
name: 'index',
component: () => import('@/views/roleManage/index'),
meta: { title: '首页', authority: ['role_manage'], keepAlive: false }
},
{
path: 'detail',
name: 'detail',
// hidden: true,
component: () => import('@/views/roleManage/detail'),
meta: { title: '详情', authority: ['role_manage'], keepAlive: false }
}
]
},
//echarts
{
path: '/myecharts',
redirct: '/myecharts/index',
name: 'myecharts',
component: Layout,
meta: { title: 'myecharts', authority: ['role_manage'] },
noDropdown: true,
children: [
{
path: 'myecharts',
name: 'myecharts',
component: () => import('@/views/myecharts/index'),
meta: { title: 'myecharts', authority: ['role_manage'], keepAlive: false }
}
]
},
//watermark
{
path: '/watermark',
redirct: '/watermark/index',
name: 'watermark',
component: Layout,
meta: { title: 'watermark', authority: ['role_manage'] },
noDropdown: true,
children: [
{
path: 'watermark',
name: 'watermark',
component: () => import('@/views/watermark/index'),
meta: { title: 'watermark', authority: ['role_manage'], keepAlive: false }
}
]
},
//timer
{
path: '/timer',
redirct: '/timer/index',
name: 'timer',
component: Layout,
meta: { title: 'timer', authority: ['role_manage'] },
noDropdown: true,
children: [
{
path: 'timer',
name: 'timer',
component: () => import('@/views/timer/index'),
meta: { title: 'timer', authority: ['role_manage'], keepAlive: false }
}
]
},
//nav
{
path: '/navmenu/index',
redirct: '/navmenu/index',
name: 'navmenu',
component: Layout,
meta: { title: 'navmenu', authority: ['nav_manage'] },
noDropdown: true,
children: [
{
path: 'navmenu',
name: 'navmenu',
component: () => import('@/views/navmenu/index'),
meta: { title: 'navmenu', authority: ['nav_manage'], keepAlive: false }
},
{
path: '/navmenu/menu1',
name: 'menu1',
hidden:true,
component: () => import('@/views/navmenu/menu1'),
meta: { title: 'menu1', authority: ['nav_manage'], keepAlive: false }
}
]
},
//分页查询
{
path: '/userPager',
redirct: '/pager/userpager',
name: 'userpager',
component: Layout,
meta: { title: '用户分页', authority: ['user_manage'] },
noDropdown: true,
children: [
{
path: 'index',
name: 'index',
component: () => import('@/views/pager/userpager'),
meta: { title: '用户分页', authority: ['user_manage'], keepAlive: false }
}
]
},
//select
{
path: '/select',
redirct: '/select/index',
name: 'select',
component: Layout,
meta: { title: 'select', authority: ['user_manage'] },
noDropdown: true,
children: [
{
path: 'index',
name: 'index',
component: () => import('@/views/select/index'),
meta: { title: 'select', authority: ['user_manage'], keepAlive: false }
},
{
path: 'user',
name: 'user',
component: () => import('@/views/select/user'),
meta: { title: 'user', authority: ['user_manage'], keepAlive: false }
},
{
path: 'tree',
name: 'tree',
component: () => import('@/views/select/tree'),
meta: { title: 'tree', authority: ['user_manage'], keepAlive: false }
},
{
path: 'treeselect',
name: 'treeselect',
component: () => import('@/views/select/treeselect'),
meta: { title: 'treeselect', authority: ['user_manage'], keepAlive: false }
}
]
},
//css
{
path: '/add',
redirct: '/css/add',
name: 'add',
component: Layout,
meta: { title: 'add', authority: ['user_manage'] },
noDropdown: true,
children: [
{
path: 'add1',
name: 'add1',
component: () => import('@/views/css/add1'),
meta: { title: 'add1', authority: ['user_manage'], keepAlive: false }
},
{
path: 'addmodel',
name: 'addmodel',
component: () => import('@/views/css/addmodel'),
meta: { title: 'addmodel', authority: ['user_manage'], keepAlive: false }
},
{
path: 'student',
name: 'student',
component: () => import('@/views/css/student'),
meta: { title: 'student', authority: ['user_manage'], keepAlive: false }
}
]
},
]
export default new Router({
// mode: 'history', // 后端支持可开
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
})
(2)权限拦截js:
import { asyncRouterMap, constantRouterMap } from '@/router/index'
/**
* 通过meta.authority判断是否与当前用户权限匹配
* @param authorities
* @param route
*/
function hasPermission(authorities, route) {
if (route.meta && route.meta.authority) {
return authorities.some(authority => route.meta.authority.indexOf(authority) >= 0)
} else {
return true
}
}
/**
* 递归过滤异步路由表,返回符合用户角色权限的路由表
* @param asyncRouterMap
* @param authorities
*/
function filterAsyncRouter(asyncRouterMap, authorities) {
const accessedRouters = asyncRouterMap.filter(route => {
if (hasPermission(authorities, route)) {
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, authorities)
}
return true
}
return false
})
return accessedRouters
}
const permission = {
state: {
routers: constantRouterMap,
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers
state.routers = constantRouterMap.concat(routers)
}
},
actions: {
GenerateRoutes({ commit }, data) {
return new Promise(resolve => {
const { authorities } = data
let accessedRouters
if (authorities.indexOf('admin') >= 0) {
accessedRouters = asyncRouterMap
} else {
accessedRouters = filterAsyncRouter(asyncRouterMap, authorities)
}
commit('SET_ROUTERS', accessedRouters)
resolve()
})
}
}
}
export default permission
(3)login.vue:
登录
取消
(4)navbar菜单页:
midtest1
midtest2
midtest3
二级菜单
midtest41
midtest42
三级菜单
midtest51
三级子菜单
midtest521
midtest522
(5)菜单页:随便看几个:
midtest1点击跳转
midtest3
midtest522
三、navbar菜单权限动态控制:上面的例子中,navbar的菜单权限是写死的,不同角色的用户登进来看到的菜单都是一样的,这里做下动态权限。
1、方法1:在router中控制权限:如现在给midtest2做权限控制:将整个Navbar的router放到asyncRouterMap下,并给midtest2的路由改为:
{
path: 'midtest2',
name: 'midtest2',
meta: { title: 'midtest2', authority: ['role_manage'] },
component: () => import('@/views/midtest/midtest2')
}
这样如果某个用户没有role_manager的权限,点击midtest2会跳转到空白页,但是该用户还是可以看到midtest2的菜单导航。
2、方法2:给navbar菜单导航做权限控制:
(1)、数据库:
配置11个菜单:
并给两个用户配置navbar菜单权限:
(2)后端代码:
@RequestMapping("/getNavMenu")
private ResponseMessage getNavMenu(){
JWTUserDTO jwtUser = (JWTUserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
List menuDTOS = navMenuService.getNavMenu(jwtUser.getUserName());
return ResponseMessage.success(menuDTOS);
}
package com.demo.service.impl;
import com.demo.dao.NavMenuDao;
import com.demo.dto.NavMenuDTO;
import com.demo.service.NavMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("navMenuService")
public class NavMenuServiceImpl implements NavMenuService {
@Autowired
private NavMenuDao navMenuDao;
@Override
public List getNavMenu(String userAccount) {
//一级菜单
List navMenuDTOList = navMenuDao.getNavMenu(userAccount,0);
//子菜单
for(NavMenuDTO navMenuDTO : navMenuDTOList){
//二级菜单
Integer menuId = navMenuDTO.getId();
List secondChildNavList = navMenuDao.getNavMenu(userAccount,menuId);
navMenuDTO.setChildList(secondChildNavList);
//三级菜单
for(NavMenuDTO secondChild : secondChildNavList){
Integer secondMenuId = secondChild.getId();
List thirdChildNavList = navMenuDao.getNavMenu(userAccount,secondMenuId);
secondChild.setChildList(thirdChildNavList);
}
}
return navMenuDTOList;
}
}
(3)前端代码:
登录成功后调用getNavMenu接口从后台获取navbar菜单列表,存储到store中,改造下上面例子中的index菜单页代码:
{{item.menuName}}
{{item.menuName}}
{{second.menuName}}
{{second.menuName}}
{{third.menuName}}
这里最多有三级菜单,如果菜单级别比较多,写在一个文件里比较复杂,可以封装成子组件调用,子组件里再调用组件自己,形成递归。
看下效果:先是zhangsan登录:
再退出切换成lisi登录: