vue element plus 管理系统路由菜单简要设计(后端获取菜单)

1 需求

  • 管理系统“菜单”由后端接口返回,前端需要根据后端返回的“菜单”数组,构造路由,渲染侧栏菜单
  • 有些菜单是子菜单,有对应的路由,但是不在侧栏显示(比如一些详情页面) 注:这里的“菜单”,不是字面意思的菜单,即可以是菜单也可以是按钮,如果是菜单则对应路由

2 分析

一般我们“菜单“保存在数据库时,不会仅仅保存路由相关参数,还会增加一下自定义参数,类似下面的数据结构:

const menu = {
  id: "1",
  pid: "-1", // 父id
  nameCn: "平台管理", //中文名
  type: "menu", //类别:menu 菜单,button 按钮
  icon: "platform", //图标
  routeName: "platform", //路由名
  routePath: "/platform", //路由地址
  routeLevel: 1, //路由级别: 一级路由(左侧显示)  二级路由(左侧不显示)
  componentPath: "", //组件路径
  sort: 1, //排序
  children: [],
};

所以需要手动构造路由,渲染侧栏菜单

需要注意的地方

  • 通过设置 routeLevel 字段来判断当前“菜单“是否在左侧菜单显示
  • 添加 el-menu 的 router 属性,这样可以点击 menu 自动跳转到 index 绑定的路径,否则需要绑定 click 事件,进行手动跳转(适用于需要跳转外链的情况,需要再递归菜单时进行判断,不给index赋值path)
  • 如果当前“菜单“存在 children,但是 children 所有 child 是二级路由并且 path 没有以“/”开头(如下面路由中的硬件管理),那么需要将一个 Empty.vue 组件指向当前“菜单“,并且创建一个 path 为空的 child 来匹配当前“菜单“,否则二级路由无法跳转(无法跳转指的是是当前“菜单“组件路径直接配置目的组件路径)
  • 如果当前“菜单“存在 children,但是 children 中有 child 的 path 没有以“/”开头,在构造左侧菜单时,需要拼接祖先 path 后再赋值给 index,否则无法跳转 这里使用 router.getRoutes()返回的所有路由,并且使用路由 name 匹配,这样比自己递归拼接方便,如下面 MenuItem.vue 组件中使用的 processRoutePath 函数

3 实现

效果图:

vue element plus 管理系统路由菜单简要设计(后端获取菜单)_第1张图片

vue element plus 管理系统路由菜单简要设计(后端获取菜单)_第2张图片

vue element plus 管理系统路由菜单简要设计(后端获取菜单)_第3张图片

3.1 目录结构

vue element plus 管理系统路由菜单简要设计(后端获取菜单)_第4张图片

3.2 代码:

components/SvgIcon.vue







layout/index.vue






layout/components/MenuItem.vue





router/index.ts

import { createRouter, createWebHistory } from "vue-router";

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: "/",
      name: "index",
      component: () => import("../layout/index.vue"),
      meta: {
        title: "index",
        sort: 1,
      },
    },
  ],
  // 刷新时,滚动条位置还原
  scrollBehavior: () => ({ left: 0, top: 0 }),
});

export const menus = [
  {
    id: "1",
    pid: "-1", // 父id
    nameCn: "平台管理", //中文名
    type: "menu", //类别:menu 菜单,button 按钮
    icon: "platform", //图标
    routeName: "platform", //路由名
    routePath: "/platform", //路由地址
    routeLevel: 1, //路由级别: 一级路由(左侧显示)  二级路由(左侧不显示)
    componentPath: "", //组件路径
    sort: 1, //排序
    children: [
      {
        id: "1-1",
        nameCn: "角色管理",
        permission: "",
        type: "menu",
        pid: "1",
        icon: "role",
        iconColor: "",
        routeName: "role",
        routePath: "role",
        routeLevel: 1,
        componentPath: "/platform/role/index.vue",
        sort: 1,
        children: [
          {
            id: "1-1-1",
            nameCn: "新增",
            permission: "account:add",
            type: "button",
            pid: "1-1",
            icon: "user",
            iconColor: "",
            routeName: "",
            routePath: "",
            routeLevel: null,
            componentPath: "",
            sort: 1,
            children: [],
          },
        ],
      },
      {
        id: "1-2",
        nameCn: "账户管理",
        permission: "",
        type: "menu",
        pid: "1",
        icon: "user",
        iconColor: "",
        routeName: "account",
        routePath: "account",
        routeLevel: 1,
        componentPath: "/platform/account/index.vue",
        sort: 2,
        children: [],
      },
    ],
  },
  {
    id: "2",
    pid: "-1",
    nameCn: "资产管理",
    type: "menu",
    icon: "property",
    routeName: "",
    routePath: "/property",
    routeLevel: 1,
    componentPath: "",
    sort: 2,
    children: [
      {
        id: "2-1",
        pid: "2",
        nameCn: "文档管理",
        permission: "",
        type: "menu",
        icon: "document",
        iconColor: "",
        routeName: "document",
        routePath: "document",
        routeLevel: 1,
        componentPath: "/property/document/index.vue",
        sort: 1,
        children: [],
      },
      {
        id: "2-2",
        pid: "2",
        nameCn: "硬件管理",
        permission: null,
        type: "menu",
        icon: "hardware",
        iconColor: "",
        routeName: "",
        routePath: "hardware",
        routeLevel: 1,
        componentPath: "/property/layout/Empty.vue",
        sort: 2,
        children: [
          {
            id: "2-2-1",
            pid: "2-2",
            nameCn: "硬件管理",
            permission: null,
            type: "menu",
            icon: "",
            routeName: "hardware",
            routePath: "",
            routeLevel: 2,
            componentPath: "/property/hardware/index.vue",
            sort: 1,
            children: [],
          },
          {
            id: "2-2-2",
            pid: "2-2",
            nameCn: "硬件配置",
            permission: null,
            type: "menu",
            icon: "",
            routeName: "config",
            routePath: "config",
            routeLevel: 2,
            componentPath: "/property/hardware/Config.vue",
            sort: 2,
            children: [],
          },
        ],
      },
    ],
  },
];

const initRouter = (routerTree: any) => {
  const routerArr: any = [];
  routerTree.forEach((item: any) => {
    if (item.type === "menu") {
      routerArr.push({
        meta: { title: item.nameCn },
        name: item.routeName || "",
        path: item.routePath || "",
        component: item.componentPath
          ? () => import(/* @vite-ignore */ "../view" + item.componentPath)
          : "",
        children: item.children ? initRouter(item.children) : [],
      });
    }
  });
  return routerArr;
};

const routers = initRouter(menus);
routers.forEach((item: any) => {
  router.addRoute("index", item);
});

console.log(router.getRoutes());

export default router;

view/platform/account/index.vue


view/platform/role/index.vue


view/property/layout/Empty.vue


view/property/hardware/index.vue



view/property/hardware/Config.vue


view/property/document/index.vue



你可能感兴趣的:(scene,vue,element,plus,vue.js,前端,javascript,elementui)