VUE--ElementUI--动态菜单+路由(五)

一、动态菜单

(一). 前端代码

  1. 登录页



  1. 侧边栏


  1. 主页



  1. 令牌存储store.js

 var store=window.localStorage;

export function setToken(val){
    store.token=val;
}

export function deleteKey(key){
    store.removeItem(key)
}

export function getToken(){
    return store.token;
}

  1. 路由处理router.js
import dynamicRouter from "@/router/dynamicRouter.js";
import { getToken } from '@/utils/store.js';
import Vue from 'vue';
import Router from 'vue-router';
import { getRouter } from "@/api/menu.js";

Vue.use(Router)
/**
 * 重写路由的push方法
 */
const routerPush = Router.prototype.push
Router.prototype.push = function push(location) {
  return routerPush.call(this, location).catch(error=> error)
}

const router = new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/',
      name: 'login',
      component: () => import('@/views/Login.vue')
    }
  ]
});
/**
 * 避免循环执行
 */
let newRoutes = null;
router.beforeEach((to, from, next) => {
  // 判断是否是登录界面
  if (to.path != '/') {
    // 从获取store中Token
    if (getToken()) {
      // 刷新动态路由丢失
      if (!newRoutes) {
        // 调用API获取动态路由
        getRouter().then(res => {
          res.data.data.forEach(element => {
            // 重要:赋值给变量
            let value = element.component;
            element.component = function component(resolve) {
              require(["@/views" + value], resolve);
            };
          });
          dynamicRouter.routes[0].children = res.data.data;
          newRoutes = dynamicRouter.routes;
          // 添加路由数据
          router.addRoutes(newRoutes);
          next({ ...to, replace: true });
        });
      } else {
        next()
      }
    }else{
      next("/");
    }
  } else {
    // 如果是登录界面放行
    next();
  }
});

export default router;
  1. 动态路由定义dynamicRouter.js
/**
 * 动态路由定义
 */
let dynamicRouter = {
    routes: [
        {
            path: "/layout",
            name: "layout",
            component: () => import("@/views/layout/Layout.vue"),
            children: []
        }
    ]
}

export default dynamicRouter;

  1. 登录API
import request from "@/utils/request.js";
/**
 * 登录方法
 * @param {} data 
 */
export function login(data){
    return request({
        url:"/admin-service/auth/login",
        method:"post",
        data:data
    });
}
  1. 菜单路由API
import request from "@/utils/request.js";

/**
 * 获取菜单数据
 */
export function getMenu(){
    return request({
        url:"/admin-service/menu/admin",
        method:"get"
    });
}
/**
 * 获取路由数据
 */
export function getRouter(){
    return request({
        url:"/admin-service/menu/router/admin",
        method:"get"
    });
}

(二). 后台代码

  1. 数据表结构与数据
    在此只列表菜单表,其它表,用户、角色、权限未列。
CREATE TABLE `system_menu`  (
  `id` bigint(20) NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由名',
  `path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路径',
  `menu_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '显示名称',
  `parent_id` int(11) NULL DEFAULT NULL COMMENT '父级ID',
  `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图标',
  `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组件地址',
  `deleted` int(11) NULL DEFAULT NULL COMMENT '逻辑删除(1 已删除 0未删除)',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of system_menu
-- ----------------------------
INSERT INTO `system_menu` VALUES (1, 'userManage', '', '会员管理', 0, 'el-icon-s-custom', NULL, 0, '2019-09-11 14:33:17', NULL);
INSERT INTO `system_menu` VALUES (2, 'user', 'user', '会员列表', 1, 'el-icon-s-custom', '/user/index.vue', 0, '2019-09-11 14:35:26', NULL);
INSERT INTO `system_menu` VALUES (3, 'role', 'role', '角色管理', 0, 'el-icon-s-custom', '/role/index.vue', 0, '2019-09-12 10:49:40', NULL);
INSERT INTO `system_menu` VALUES (4, 'goods', '', '商品管理', 0, 'el-icon-shopping-cart-full', NULL, 0, '2019-09-19 10:28:36', NULL);
INSERT INTO `system_menu` VALUES (5, 'category', 'category', '分类管理', 4, NULL, '/category/index.vue', 0, '2019-09-19 10:29:58', NULL);
INSERT INTO `system_menu` VALUES (6, 'goods', 'goods', '商品管理', 4, NULL, '/goods/index.vue', 0, '2019-09-19 10:30:52', NULL);

  1. 菜单VO类代码
@Data
public class MenuVO {
    private Long id;
    private String title;
    private String icon;
    private String key;
    private String path;
    private Set children;
}

  1. 路由VO类代码
@Data
public class RouterVO {
    /**
     * 名称
     */
    private String name;
    /**
     * 路径
     */
    private String path;
    /**
     * 组件
     */
    private String component;
}

  1. 菜单路由业务类代码
    @Override
    public List getMenusByUsername(String username) {
        // 1.根据用户名查找角色
        List roles = roleMapper.getRolesByUsername(username);
        List menuVOList=new ArrayList<>();
        for (RoleVO roleVO : roles) {
            List lists = menuMapper.getMenusByRoleId(roleVO.getId());
            for (Menu menu:lists) {
                if(null!=menu&&null!=menu.getParentId()&&menu.getParentId()==0) {
                    MenuVO menuVO = new MenuVO();
                    menuVO.setId(menu.getId());
                    menuVO.setKey(menu.getId().toString());
                    menuVO.setTitle(menu.getMenuName());
                    menuVO.setIcon(menu.getIcon());
                    menuVO.setPath(menu.getPath());
                    menuVO.setChildren(this.getSubMenu(lists,menuVO));
                    // 添加一级菜单数据
                    menuVOList.add(menuVO);
                }
            }
        }
        return menuVOList;
    }

    /**
     * 获取子菜单
     * @param lists
     * @param menuVO
     * @return
     */
    private Set getSubMenu( List lists,  MenuVO menuVO ){
        Set menuVOList=new HashSet<>();
        for (Menu menu0:lists) {
            if(menuVO.getId()==menu0.getParentId()){
                MenuVO menuVO0 = new MenuVO();
                menuVO0.setId(menu0.getId());
                menuVO0.setKey(menu0.getId().toString());
                menuVO0.setPath(menu0.getPath());
                menuVO0.setIcon(menu0.getIcon());
                menuVO0.setTitle(menu0.getMenuName());
                menuVOList.add(menuVO0);
                // 添加到集合
                Set menuVOSet=this.getSubMenu(lists,menuVO0);
                menuVO0.setChildren(menuVOSet);
            }
        }
        return menuVOList;
    }
}
    /**
     * 获取路由
     * @param username
     * @return
     */
    @Override
    public List getRouter(String username) {
        // 1. 根据用户名查找角色
        List roles = roleMapper.getRolesByUsername(username);
        List routerVOList=new ArrayList<>();
        for (RoleVO roleVO : roles) {
            // 2. 通过角获取菜单
            List lists = menuMapper.getMenusByRoleId(roleVO.getId());
            for (Menu menu:lists) {
                // 目录为空
                if(StringUtils.isNotEmpty(menu.getPath())) {
                    RouterVO routerVO = new RouterVO();
                    routerVO.setName(menu.getName());
                    routerVO.setComponent(menu.getComponent());
                    routerVO.setPath(menu.getPath());
                    // 添加一级菜单数据
                    routerVOList.add(routerVO);
                }
            }
        }
        return routerVOList;
    }
}

  1. 获取菜单与路由控制器代码
    @GetMapping("{username}")
    public Result> getMenus(@PathVariable("username") String username) {
        return Result.ok(adminService.getMenusByUsername(username));
    }

    @GetMapping("router/{username}")
    public Result> getRouter(@PathVariable("username") String username) {
        return Result.ok(menuService.getRouter(username));
    }

二、常见问题

  1. 动态路中添加之坑
    vue lazy recursive ^./.*$
    解决:
    数据赋值给局部变量后添加。
 let value = element.component;
            element.component = function component(resolve) {
              require(["@/views" + value], resolve);
            };
  1. 刷新页面空白
    解决:
    在beforeEach中读取后台数据进行路由添加。

你可能感兴趣的:(VUE--ElementUI--动态菜单+路由(五))