一种简单的VUE动态加载菜单方案

787 阅读2分钟

前言

最近公司重构了一套营业厅的前端页面,可以由于设计的不好,导致各种问题频发,其中我认为设计的最不好的一个就是路由,路由由于使用的还是router.js,文件又大,上千个菜单都配置到一个文件里面,各个团队都有自己的页面,乱七八糟,我理解这样还不如放到数据库,然后根据数据库可以指定路由名、组件名、归属团队等信息,使用的时候根据权限去动态加载路由,而现在是一股脑全部加载进去,导致前端项目卡顿,操作员使用不畅。

1、后端接口返回菜单路径等(和router.js中的格式一样)

2、前端动态渲染

2.1、vuex配置

import Vue from 'vue'
import Vuex from 'vuex'
// vuex状态管理工具
Vue.use(Vuex)

export default new Vuex.Store({
        state:{
            routes: []
        },
        mutations:{
            initRoutes(state,data) {
                state.routes = data;
            }
        },
        actions:{

        }
    })

2.2、菜单工具类(用于解析后端返回的json菜单)

// 菜单工具类,用于将后端返回的菜单格式化为符合路由写法的格式
import {getRequest} from "./api";
// 加载所有菜单
export const initMenu=(router,store) => {

    if (store.state.routes.length > 0) {
        return;
    }


    getRequest("/system/config/menu").then(
        data=>{
            if (data) {
                let fmtRoutes = formatRoutes(data);
                router.addRoutes(fmtRoutes);
                store.commit('initRoutes', fmtRoutes);
            }
        }
    )
}

export const formatRoutes = (routes) => {
    let fmRoutes = [];
    routes.forEach(router => {
        let {
            path,
            component,
            name,
            meta,
            iconCls,
            children
        } = router;

        if (children && children instanceof Array) {
            children = formatRoutes(children);
        }

        let fmRouter={
            path:path,
            name:name,
            iconCls:iconCls,
            meta:meta,
            children:children,
            component(resolve) {
                if (component.startsWith("Home")) {
                    require(['../views/'+component+'.vue'],resolve); // 动态导入
                } else if (component.startsWith("Emp")) {
                    require(['../views/emp/'+component+'.vue'],resolve); // 动态导入
                } else if (component.startsWith("Per")) {
                    require(['../views/per/'+component+'.vue'],resolve); // 动态导入
                } else if (component.startsWith("Sal")) {
                    require(['../views/sal/'+component+'.vue'],resolve); // 动态导入
                } else if (component.startsWith("Sta")) {
                    require(['../views/sta/'+component+'.vue'],resolve); // 动态导入
                } else if (component.startsWith("Sys")) {
                    require(['../views/sys/'+component+'.vue'],resolve); // 动态导入
                }
            }
        }

        fmRoutes.push(fmRouter)
    })
    return fmRoutes;
}

2.3 、路由增加前置守卫(用于监听加载)

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../views/Login.vue'
import {initMenu} from "../utils/menus";
import store from "../store";

Vue.use(VueRouter)


// 引入组件
const routes = [
  {
    path: '/',
    name: 'Login',
    component: Login,
    hidden: true
  }
]

const router = new VueRouter({
  routes
})
// 引入前置守卫,类似于过滤器,监听操作
router.beforeEach((to, from, next) => {
  // 防止刷新页面后菜单未加载,添加前置守卫
  if (to.path == '/') {
    next();
  } else {
    initMenu(router,store);
    next();
  }
})
export default router

2.4、使用

                        <!--<el-menu @select="menuClick">-->
                        <el-menu router unique-opened>

                            <!--之前从路由中获取<el-submenu index="1" v-for="(item,index) in this.$router.options.routes" v-if="!item.hidden" :key="index">-->
                            <el-submenu :index="index + ''" v-for="(item,index) in routes" v-if="!item.hidden" :key="index">
                                <template slot="title">

                                    <i class="el-icon-location"></i>
                                    <span>{{item.name}}</span>
                                    <!--<span>test</span>-->
                                </template>
                                <el-menu-item-group>
                                    <el-menu-item :index="child.path" v-for="(child,indexj) in item.children" :key="indexj">{{child.name}}</el-menu-item>
<!--                                    <el-menu-item index="/test1">1</el-menu-item>
                                    <el-menu-item index="/test2">2</el-menu-item>-->
                                </el-menu-item-group>

                            </el-submenu>
                        </el-menu>

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第29天,点击查看活动详情