一个vuex+vue-router实现的动态树形菜单

所谓动态菜单,就是菜单数据从后台加载,前端接收到的是一个JSON,前端代码解析后渲染相应的菜单信息,相应的路由也应该是动态加载的。

TreeDetail.vue




TreeView.vue




TreeViewItem.vue




初始化菜单信息以及菜单点击相关逻辑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




静态图效果:


微信截图_20190527174725.png

参考了网上开源的一个tree组件,原文找不到了。

动态菜单需要考虑每次都去后台加载,都需要连接查询,所以后台做了优化,菜单json存到redis中。
前端也做了优化,菜单加载后使用sessionStorage存储到本地,优先从本地加载,加载不到再发起后台请求。
递归遍历菜单json后,同时将路由信息也渲染一下,this.$router.addRoutes(routerArr),参数是数组,不是对象。如果链接不在路由信息中跳到404页面,路由信息从上向下查找,所以404的通配路由信息要放在最后,也就是上面未匹配到,最后匹配进入通配路由中,所以在动态路由加载完后,单独再将该路由信息添加到最后。

你可能感兴趣的:(一个vuex+vue-router实现的动态树形菜单)