Vue动态路由实现左侧菜单
一、后端代码
1、后台Controller代码,从sys_menu获取菜单信息
/** * 获取路由信息
* * @return 路由信息
*/
@GetMapping("getRouters")
public AjaxResult getRouters() {
//获取用户身份信息
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
// 用户信息
SysUser user = loginUser.getUser();
// 根据用户ID获取对应的菜单信息列表 List
// 将获取的菜单信息列表封装成前端所需要的格式
return AjaxResult.success(menuService.buildMenus(menus));
}
2、后台menuService 对应部分代码
/** * 构建前端路由所需要的菜单 * * @param menus 菜单列表 * @return 路由列表 */ @Override
public List
{
List
for (SysMenu menu : menus) {
RouterVo router = new RouterVo(); //router.setHidden("1".equals(menu.getVisible())); router.setName(getRouteName(menu)); router.setPath(getRouterPath(menu)); router.setComponent(getComponent(menu));
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), true));
List
if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType()))
{
router.setAlwaysShow(true); router.setRedirect("noRedirect"); router.setChildren(buildMenus(cMenus));
} else if (isMeunFrame(menu))
{
List
RouterVo children = new RouterVo(); children.setPath(menu.getPath()); children.setComponent(menu.getComponent()); children.setName(StringUtils.capitalize(menu.getPath()));
children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), true)); childrenList.add(children); router.setChildren(childrenList);
}
routers.add(router);
}
return routers;
}
/** * 获取路由名称
* * @param menu 菜单信息
* @return 路由名称
*/
public String getRouteName(SysMenu menu) {
String routerName = StringUtils.capitalize(menu.getPath());
// 非外链并且是一级目录(类型为目录)
if (isMeunFrame(menu)) {
routerName = StringUtils.EMPTY;
}
return routerName;
}
/** * 获取路由地址
* * @param menu 菜单信息
* @return 路由地址
*/
public String getRouterPath(SysMenu menu) {
String routerPath = menu.getPath();
// 非外链并且是一级目录(类型为目录)
if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType()) ) {
routerPath = "/" + menu.getPath();
}
// 非外链并且是一级目录(类型为菜单) else if (isMeunFrame(menu)) {
routerPath = "/";
}
return routerPath;
}
/** * 获取组件信息
* * @param menu 菜单信息
* @return 组件信息
*/
public String getComponent(SysMenu menu) {
String component = UserConstants.LAYOUT;
if (StringUtils.isNotEmpty(menu.getComponent()) && !isMeunFrame(menu))
{
component = menu.getComponent();
} else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu))
{
component = UserConstants.PARENT_VIEW;
}
return component;
}
/** * 是否为菜单内部跳转
* * @param menu 菜单信息
* @return 结果
*/
public boolean isMeunFrame(SysMenu menu) {
return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType());
}
/** * 是否为parent_view组件
* * @param menu 菜单信息
* @return 结果 */
public boolean isParentView(SysMenu menu) {
return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType());
}
二、前端代码
1、配置路由:在src的下面的router文件夹下创建index.js (\src\router\index.js) 文件 import Vue from 'vue'
import VueRouter from 'vue-router'
import Layout from '@/layout' Vue.use(VueRouter)
// 公用路由
export const constantRoutes = [
{
path: '/login',
name: 'login',
component: () => import('@/views/login'), hidden: true
},
{
path: '/register',
component: () => import('@/views/register'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error/404'),
hidden: true
},
{ path: '/401',
component: () => import('@/views/error/401'),
hidden: true
},
{ path: '',
component: Layout,
redirect: 'index',
children: [
{ path: 'index',
// component: () => import('@/views/index'),
component: (resolve) => require(['@/views/index'], resolve),// 打包环境-主页
name: 'Index',
meta: { title: '首页', icon: 'dashboard', noCache: true, affix: true },
hidden: false } ] } ]
const router = new VueRouter({
mode: 'history',
// 去掉url中的#
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes })
export default router
2、在src下面创建permission.js (\src\permission.js) 文件
import router from './router'
import store from './store'
import NProgress from 'nprogress'
// Progress 进度条
import 'nprogress/nprogress.css'
// Progress 进度条样式
import { Message } from 'element-ui' import { getToken } from '@/utils/auth'
// 验权
const whiteList = ['/login'] // 不重定向白名单
router.beforeEach((to, from, next) => { NProgress.start()
if (getToken()) {
if (to.path === '/login') {
next({ path: '/' })
NProgress.done()
} else {
if (store.getters.roles.length === 0) {
store.dispatch('GetInfo').then(res => {
// 拉取用户信息
const menus = res.menus
const username = res.username
store.dispatch('GenerateRoutes', { menus, username }).then(accessRoutes => {
// 生成可访问的路由表
router.addRoutes(accessRoutes)
// 动态添加可访问路由表
global.antRouter = accessRoutes
// 将路由数据传递给全局变量,做侧边栏菜单渲染工作
next({ ...to, replace: true })
})
}).catch((err) => {
store.dispatch('LogOut').then(() => {
Message.error(err || 'Verification failed, please login again')
next({ path: '/' })
})
})
} else {
next()
} } } else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next('/login')
NProgress.done()
} }
})
router.afterEach(() => {
NProgress.done()
// 结束Progress
})
3、在src下面store\modules文件夹下创建permission.js (\src\store\modules\permission.js) 文件
import { constantRoutes } from '@/router/index'
import { getRouters } from '@/api/menu'
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView'
const permission = {
state: {
routers: [],
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers
state.routers = constantRoutes.concat(routers)
} },
actions: {
GenerateRoutes ({ commit }, data) {
return new Promise(resolve => {
// 向后端请求路由数据
getRouters().then(res => {
const sdata = JSON.parse(JSON.stringify(res.data))
const accessedRoutes = filterAsyncRouter(sdata, false, true)
commit('SET_ROUTERS', accessedRoutes)
resolve(accessedRoutes)
}) })
} } }
// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter (asyncRouterMap, lastRouter = false, type = false)
{
return asyncRouterMap.filter(route => {
if (route.component) {
// Layout ParentView 组件特殊处理
if (route.component === 'Layout') {
route.component = Layout
} else if (route.component === 'ParentView') {
route.component = ParentView
} else {
route.component = loadView(route.component)
}
}
if (route.children != null && route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, route, type)
}
return true
}) }
export const loadView = (view) => {
return (resolve) => require([`@/views/${view}`], resolve)
}
export default permission
4、在src下面store文件夹下创建index.js (\src\store\index.js) 文件
import Vue from 'vue'
import Vuex from 'vuex'
import permission from './modules/permission'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: { permission }, getters
})
export default store
5、在src下面store文件夹下创建getters.js (\src\store\getters.js) 文件
const getters = {
addRouters: state => state.permission.addRouters,
routers: state => state.permission.routers
}
export default getters
6、在src下面store\modules文件夹下创建permission.js (\src\store\modules\permission.js) 文件
import { constantRoutes } from '@/router/index'
import { getRouters } from '@/api/menu'
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView'
const permission = {
state: {
routers: [],
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers
state.routers = constantRoutes.concat(routers)
}
},
actions: {
GenerateRoutes ({ commit }, data) {
return new Promise(resolve => {
// 向后端请求路由数据
getRouters().then(res => {
const sdata = JSON.parse(JSON.stringify(res.data))
console.log('sdata', sdata)
const accessedRoutes = filterAsyncRouter(sdata, false, true)
console.log('accessedRoutes', accessedRoutes)
commit('SET_ROUTERS', accessedRoutes)
resolve(accessedRoutes)
}) })
} } }
// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter (asyncRouterMap, lastRouter = false, type = false) {
return asyncRouterMap.filter(route => {
if (route.component) {
// Layout ParentView 组件特殊处理
if (route.component === 'Layout') {
route.component = Layout
} else if (route.component === 'ParentView') {
route.component = ParentView
} else {
route.component = loadView(route.component)
}
}
if (route.children != null && route.children && route.children.length) {
route.children = filterAsyncRouter(route.children, route, type)
} return true
}) }
export const loadView = (view) => {
return (resolve) => require([`@/views/${view}`], resolve)
}
export default permission
7、在src下面layout文件夹下创建index.vue (\src\layout\index.vue) 文件
.app-wrapper {
position: relative;
height: 100%;
width: 100%;
}
8、在src下面layout\components文件夹下创建AppMain.vue
(\src\layout\components\AppMain.vue) 文件
9、在src下面layout\components文件夹下创建Navbar.vue
(\src\layout\components\Navbar.vue) 文件
服务业务支撑系统
{{ name }}
{{ name }} 所属单位:{{ company }}
安全退出
10、在src下面layout\components文件夹下创建index.js (\src\layout\components\index.js) 文件
export { default as AppMain } from './AppMain'
export { default as Navbar } from './Navbar'
export { default as sidebar } from './sidebar/index.vue'
11、在src下面layout\components\sidebar文件夹下创建index.vue (\src\layout\components\sidebar\index.vue) 文件
12、在src下面layout\components\sidebar文件夹下创建sidebarItem.vue (\src\layout\components\sidebar\sidebarItem.vue) 文件
{{item.children[0].meta.title}}
{{item.meta.title}}
{{child.meta.title}}
效果如图:
留言与评论(共有 0 条评论) “” |