所谓动态菜单,就是菜单数据从后台加载,前端接收到的是一个JSON,前端代码解析后渲染相应的菜单信息,相应的路由也应该是动态加载的。
TreeDetail.vue
TreeView.vue
TreeViewItem.vue
{{menu.resourceName}}
初始化菜单信息以及菜单点击相关逻辑menusModule.js
let menus = toArray();
function toArray() {
var obj = sessionStorage.getItem("menuJson");
return JSON.parse(obj);
}
let resourceLevelNum = 1;
let startExpand = []; // 保存刷新后当前要展开的菜单项
function setExpand(source, resourceUrl) {
let sourceItem = '';
for (let i = 0; i < source.length; i++) {
sourceItem = JSON.stringify(source[i]); // 把菜单项转为字符串
// 查找当前 resourceUrl 所对应的子菜单属于哪一个祖先菜单,并且初始路径不为'/',否则会把菜单第一个选然后选中并展开
if (sourceItem.indexOf(resourceUrl) > -1 && resourceUrl != '/') {
// debugger;
if (source[i].resourceType === 'button') { // 导航菜单为按钮
source[i].selected = true; // 设置选中高亮
source[i].expanded = true; // 设置为展开
startExpand.push(source[i]);
// 递归下一级菜单,以此类推
setExpand(source[i].childQueues, resourceUrl);
}
break;
}
}
}
const state = {
menus,
resourceLevelNum
};
const mutations = {
findParents(state, payload) {
if (payload.menu.resourceType === "button") {
payload.menu.expanded = !payload.menu.expanded;
} else if (payload.menu.resourceType === "link") {
if (startExpand.length > 0) {
for (let i = 0; i < startExpand.length; i++) {
startExpand[i].selected = false;
}
}
startExpand = []; // 清空展开菜单记录项
setExpand(state.menus, payload.menu.resourceUrl);
};
},
firstInit(state, payload) {
setExpand(state.menus, payload.url);
},
// 初始化state中的菜单信息
initStateMenus(state, payload) {
state.menus = payload.menus;
}
}
export default {
state,
mutations
};
路由index.js
// 只给初始默认路由
import Vue from 'vue';
import Router from 'vue-router';
import welcome from '../components/welcome.vue';
import error from '../components/error.vue';
Vue.use(Router)
export default new Router({
linkActiveClass: 'selected',
mode: 'history',
routes: [{
path: '/',
name: 'welcome',
component: welcome
},
{
path: '/error',
name: 'error',
component: error
}
]
})
Home.vue
静态图效果:
参考了网上开源的一个tree组件,原文找不到了。
动态菜单需要考虑每次都去后台加载,都需要连接查询,所以后台做了优化,菜单json存到redis中。
前端也做了优化,菜单加载后使用sessionStorage存储到本地,优先从本地加载,加载不到再发起后台请求。
递归遍历菜单json后,同时将路由信息也渲染一下,this.$router.addRoutes(routerArr),参数是数组,不是对象。如果链接不在路由信息中跳到404页面,路由信息从上向下查找,所以404的通配路由信息要放在最后,也就是上面未匹配到,最后匹配进入通配路由中,所以在动态路由加载完后,单独再将该路由信息添加到最后。