el-menu dynamic loading route, menu solution

First look at the effect that needs to be achieved

insert image description here
There are first-level and second-level menus here, pay attention to the parent directory of the second-level menu ("Option Settings" click will not jump, just expand the directory), and then click to go to the details page, you need to jump to a hidden route, which is not displayed in the menu insert image description here
Another thing to note is that there are two router-views here, the entire page is a router-view, which can be replaced by LoginView and HomeView (the page currently seen), and there is another router-view under HomeView, which needs to be used Display department, system, timeout, employee settings, non-conforming product list and non-conforming product details page.


All the above information needs to be reflected in the table of the database.
First, let’s see what operations need to be written directly in the code.

const routes = [
  {
    
    
    path: '',
    name: 'login',
    component: LoginView,
  }
  ,
  {
    
    
    component: HomeView,
    children: [
      {
    
    
        path: '/home',
        name: '不合格品列表',
        component: BelowStandard
      },
      {
    
    
        path: '/product/:id',
        name: '不合格品详情',
        component: BelowStandardDetail
      }
    ]
  },
  {
    
    
    component: HomeView,
    name: '选项设置',
    children: [
      {
    
    
        path: '/employee',
        name: '员工设置',
        component: EmployeeConfig,
      },
      {
    
    
        path: '/department',
        name: '部门设置',
        component: DepartmentConfig
      },
      {
    
    
        path: '/system',
        name: '系统设置',
        component: SystemConfig
      },
      {
    
    
        path: '/warn',
        name: '超时提醒',
        component: WarmConfig
      }
    ]
  },
  {
    
    
    component: HomeView,
    children: [
      {
    
    
        path: '/statistics',
        name: '统计',
        component: DailyStatistics
      }
    ]
  },
  {
    
    
    component: HomeView,
    children: [
      {
    
    
        path: '/log',
        name: '日志管理',
        component: LogManager
      }
    ]
  },
]

This is the route, when it is dynamically loaded from the database, it cannot be written here

<el-menu
            router
            active-text-color="#ffd04b"
            background-color="#000"
            class="el-menu-vertical-demo"
            :default-active="this.$route.path"
            text-color="#fff"
            @open=""
            @close=""
        >
          <el-menu-item index="/home">
            <template #title>
              不合格品列表
            </template>
          </el-menu-item>
          <el-sub-menu index="/subMenuConfig">
            <template #title>
              选项设置
            </template>
            <el-menu-item index="/department">部门设置</el-menu-item>
            <el-menu-item index="/system">系统设置</el-menu-item>
            <el-menu-item index="/warn">超时设置</el-menu-item>
            <el-menu-item index="/employee">员工设置</el-menu-item>
          </el-sub-menu>
          <el-menu-item index="/statistics">
            <span>统计</span>
          </el-menu-item>
          <el-menu-item index="/log">
            <span>日志管理</span>
          </el-menu-item>
        </el-menu>

This is because el-menu has opened the routing function, so it can jump to the route. When it is dynamically loaded, this part needs to be transformed into v-for

database

insert image description here

Explanation: The parent_id is 0 is the first-level directory, but part of the first-level directory can directly display the interface, and part of it is to expand the second-level directory. I use the component field as home/HomeView.vue to distinguish the display of the second-level directory.


Now start to write the back-end program to return the json format data of the menu.
insert image description here

List<Menu> menuList = menuMapper.getMenuByUserId(UserUtils.getLoginUser().getId());
//根据ParentId分组
Map<Integer, List<Menu>> map = menuList.stream().collect(Collectors.groupingBy(Menu::getParentId, TreeMap::new,Collectors.toList()));
List<Menu> menus = map.get(0);//一级菜单
menus.forEach(menu->{
    
    //给有二级菜单的目录设置children属性
    List<Menu> children = map.get(menu.getId());
    menu.setChildren(children);
});
return menus;

The data format queried from the database is shown in the figure, and then processed in a first-level and second-level menu, and then return to the front end

[
{
"name": "不合格品列表",
"path": "/home",
"component": "product/BelowStandard.vue",
"orderNum": 1,
"parentId": 0,
"isHidden": false,
"children": null
},
{
"name": "选项设置",
"path": "/subMenuConfig",
"component": "home/HomeView.vue",
"orderNum": 2,
"parentId": 0,
"isHidden": false,
"children": [
				{
				"name": "员工设置",
				"path": "/employee",
				"component": "config/EmployeeConfig.vue",
				"orderNum": 1,
				"parentId": 2,
				"isHidden": false,
				"children": null
				},
				{
				"name": "部门设置",
				"path": "/department",
				"component": "config/DepartmentConfig.vue",
				"orderNum": 2,
				"parentId": 2,
				"isHidden": false,
				"children": null
				},
				{
				"name": "系统设置",
				"path": "/system",
				"component": "config/SystemConfig.vue",
				"orderNum": 3,
				"parentId": 2,
				"isHidden": false,
				"children": null
				},
				{
				"name": "超时提醒",
				"path": "/warn",
				"component": "config/WarmConfig.vue",
				"orderNum": 4,
				"parentId": 2,
				"isHidden": false,
				"children": null
				}
]
},
{
"name": "统计",
"path": "/statistics",
"component": "statistics/DailyStatistics.vue",
"orderNum": 3,
"parentId": 0,
"isHidden": false,
"children": null
},
{
"name": "日志管理",
"path": "/log",
"component": "log/LogManager.vue",
"orderNum": 4,
"parentId": 0,
"isHidden": false,
"children": null
},
{
"name": "不合格品详情",
"path": "/product/:id",
"component": "product/BelowStandardDetail.vue",
"orderNum": 5,
"parentId": 0,
"isHidden": true,
"children": null
}
]

After the front end gets the data, it processes it, and then adds it to the route. I encountered a problem in the process. The vue-router4 version removed addRoutes and replaced it with addRoute
. match

Initialize the route:

router.beforeEach((to, from, next) => {
    
    //配置路由守卫
    if(to.path==='/'){
    
    
        next()
    }else if(store.state.user.id){
    
    
        initMenus(router,store,next,to)
    }else{
    
    
        next({
    
     path: '/',query: {
    
    redirect: to.path}});
    }
});

export const initMenus = (router, store,next,to) => {
    
    //按F5刷新的话vuex里的会被清空,长度变为0
    if (store.state.menu !== null) {
    
    
        next()
    }else {
    
    
        axios.get("/menu").then(response => {
    
    
            if (response) {
    
    
                let responseData = response.data
                if (responseData.flag) {
    
    
                    store.state.menu = responseData.data
                    initRoute(router,store.state)
                    next({
    
    ...to,replace:true})//解决router4版本的第一次路由不匹配问题
                } else {
    
    
                    this.$ElMessage.error('请求菜单失败')
                }
            }
        })
    }
}

const initRoute = (router,state)=> {
    
    
    const loadView = view => {
    
    //这种引入方式控制台不会报警告
        // 路由懒加载
        return () => import(`@/views/${
      
      view}`)
    };
    const menus = state.menu
    const firstLevelMenu = {
    
    
        children: [],
        component: loadView('home/HomeView.vue')
    }
    menus.forEach(menu=>{
    
    
        menu.component = loadView(menu.component)
        if(menu.children === null || menu.children.length === 0){
    
    
            firstLevelMenu.children.push(menu)
        }else{
    
    
            menu.children.forEach(children=>{
    
    
                children.component = loadView(children.component)
            })
            router.addRoute(menu)
        }
    })
    router.addRoute(firstLevelMenu)
}

After completing these configurations, the route can be dynamically loaded, and then take out the menu stored in vuex to generate el-menu The menu

in vuex is roughly as shown in the figure

<el-menu
    router
    active-text-color="#ffd04b"
    background-color="#000"
    class="el-menu-vertical-demo"
    :default-active="this.$route.path"
    text-color="#fff"
    @open=""
    @close=""
>
  <template v-for="route of this.$store.state.menu">
    <template v-if="route.children === null || route.children.length === 0"><!--一级菜单-->
      <template v-if="!route.isHidden">
        <el-menu-item :index = "route.path">
          <span>{
   
   {route.name}}</span>
        </el-menu-item>
      </template>
    </template>
    <template v-else><!--二级菜单-->
      <template v-if="!route.isHidden">
        <el-sub-menu :index = "route.path">
          <template #title>
            <span>{
   
   {route.name}}</span>
          </template>
          <template v-for="children of route.children">
            <template v-if="!children.isHidden">
              <el-menu-item :index = "children.path">
                <span>{
   
   {children.name}}</span>
              </el-menu-item>
            </template>
          </template>
        </el-sub-menu>
      </template>
    </template>
  </template>
</el-menu>

Realize the effect display
insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/lc257/article/details/127948200