Skip to content

路由和菜单

项目提供了基础的路由系统,可以根据配置文件动态生成菜单结构以及动态注册路由。

路由类型

项目中的路由分为两类:静态路由动态路由

静态路由:在项目启动时就已确定,通常包含登录页、404 等公共页面。

动态路由:在用户登录后,根据后端返回的菜单数据动态生成,通常用于控制权限和个性化导航。

静态路由

无需权限即可访问的基础页面路由,例如:登录页、注册页、404、500 等。

配置位置:src/router/routes/staticRoutes.ts

路由变量:

ts
const staticRoutes: AppRouteRecordRaw[] = [];

动态路由

需要权限控制的业务页面路由,例如:用户管理、菜单管理等。

配置位置: src/router/routes/asyncRoutes.ts

ts
const asyncRoutes: MenuListType[] = [];

路由定义

静态路由与动态路由的定义方式基本一致,请看下面的示例:

静态路由

静态路由配置
ts
export const staticRoutes: AppRouteRecordRaw[] = [
  {
    path: "/",
    redirect: HOME_PAGE,
  },
  {
    path: RoutesAlias.Login,
    name: "Login",
    component: () => import("@views/auth/login/index.vue"),
    meta: { title: "menus.login.title", isHideTab: true, setTheme: true },
  },
  {
    path: RoutesAlias.Register,
    name: "Register",
    component: () => import("@views/auth/register/index.vue"),
    meta: {
      title: "menus.register.title",
      isHideTab: true,
      noLogin: true,
      setTheme: true,
    },
  },
  {
    path: RoutesAlias.ForgetPassword,
    name: "ForgetPassword",
    component: () => import("@views/auth/forget-password/index.vue"),
    meta: {
      title: "menus.forgetPassword.title",
      isHideTab: true,
      noLogin: true,
      setTheme: true,
    },
  },
  {
    path: "/exception",
    component: Home,
    name: "Exception",
    meta: { title: "menus.exception.title" },
    children: [
      {
        path: RoutesAlias.Exception403,
        name: "Exception403",
        component: () => import("@views/exception/403/index.vue"),
        meta: { title: "403" },
      },
      {
        path: "/:catchAll(.*)",
        name: "Exception404",
        component: () => import("@views/exception/404/index.vue"),
        meta: { title: "404" },
      },
      {
        path: RoutesAlias.Exception500,
        name: "Exception500",
        component: () => import("@views/exception/500/index.vue"),
        meta: { title: "500" },
      },
    ],
  },
];

动态路由

动态路由配置
ts
export const asyncRoutes: AppRouteRecord[] = [
  {
    name: "Dashboard",
    path: "/dashboard",
    component: RoutesAlias.Home,
    meta: {
      title: "menus.dashboard.title",
      icon: "",
    },
    children: [
      {
        path: "console",
        name: "Console",
        component: RoutesAlias.Dashboard,
        meta: {
          title: "menus.dashboard.console",
          keepAlive: false,
          fixedTab: true,
        },
      },
      {
        path: "analysis",
        name: "Analysis",
        component: RoutesAlias.Analysis,
        meta: {
          title: "menus.dashboard.analysis",
          keepAlive: false,
        },
      },
      {
        path: "ecommerce",
        name: "Ecommerce",
        component: RoutesAlias.Ecommerce,
        meta: {
          title: "menus.dashboard.ecommerce",
          keepAlive: false,
        },
      },
    ],
  },
  // 一级菜单
  {
    name: "ChangeLog",
    path: "/change/log",
    component: RoutesAlias.ChangeLog,
    meta: {
      title: "menus.plan.log",
      showTextBadge: `v${__APP_VERSION__}`,
      icon: "",
      keepAlive: false,
    },
  },
];

嵌套路由

嵌套路由配置
ts
{
  path: '/system',
  name: 'System',
  component: RoutesAlias.Home,
  meta: {
    title: 'menus.system.title',
    icon: '',
    roles: ['R_SUPER', 'R_ADMIN']
  },
  children: [
    {
      path: 'nested',
      name: 'Nested',
      component: '',
      meta: {
        title: 'menus.system.nested',
        keepAlive: true
      },
      children: [
        {
          path: 'menu1',
          name: 'NestedMenu1',
          component: RoutesAlias.NestedMenu1,
          meta: {
            title: 'menus.system.menu1',
            icon: '',
            keepAlive: true
          }
        },
        {
          path: 'menu2',
          name: 'NestedMenu2',
          component: '',
          meta: {
            title: 'menus.system.menu2',
            icon: '',
            keepAlive: true
          },
          children: [
            {
              path: 'menu2-1',
              name: 'NestedMenu2-1',
              component: RoutesAlias.NestedMenu21,
              meta: {
                title: 'menus.system.menu21',
                icon: '',
                keepAlive: true
              }
            }
          ]
        },
        {
          path: 'menu3',
          name: 'NestedMenu3',
          component: '',
          meta: {
            title: 'menus.system.menu3',
            icon: '',
            keepAlive: true
          },
        }
      ]
    }
  ]
}

新建页面

你只需要在 /src/views/ 目录下创建一个页面,如:/src/views/safeguard/Server.vue

ts
<template>
  <div class="page-content">
    <h1>test page</h1>
  </div>
</template>

tips:上面的例子中我们添加了一个页面,页面 class="page-content" 这个类名可以将盒子最小高度始终撑满屏幕剩余高度

路由注册

页面创建完成后需要注册路由才能访问页面

配置文件:src/router/routes/asyncRoutes.ts

一级路由(一级菜单):

ts
export const asyncRoutes: MenuListType[] = [
  {
    path: "/test/index",
    name: "Test",
    component: "/test/index",
    meta: {
      title: "测试页",
      keepAlive: true,
    },
  },
];

完成上面的步骤后就可以访问页面了

到这里路由添加完成,访问 http://localhost:3006/safeguard/server, 如果能够正常访问,则表示路由和菜单定义成功。

多级路由(多级菜单):

ts
export const asyncRoutes: MenuListType[] = [
  {
    name: "Form",
    path: "/form",
    component: RoutesAlias.Home,
    meta: {
      title: "表单",
      icon: "&#xe721;",
      keepAlive: false,
    },
    children: [
      {
        path: "basic",
        name: "Basic",
        component: "/form/basic",
        meta: {
          title: "基础表单",
          keepAlive: true,
        },
      },
      {
        path: "step",
        name: "Step",
        component: "/form/step",
        meta: {
          title: "分步表单",
          keepAlive: true,
        },
      },
    ],
  },
];

静态路由配置:

配置文件路径: src/router/routes/staticRoutes.ts

ts
export const staticRoutes: AppRouteRecordRaw[] = [
  {
    path: "/test",
    name: "Test",
    component: () => import("@views/test/index.vue"),
    meta: { title: "测试页面", isHideTab: true, setTheme: true },
  },
];

配置完成后你可以访问:http://localhost:3006/#/test 查看新建的页面,到这里静态路由注册完成。 tips: 如果静态路由在动态路由表也配置了,需要把静态路由中的配置去除,因为动态路由会自动注册路由。

主页配置

通过配置 HOME_PAGE 属性可以定义主页路由,配置文件路径:src/router/routesAlias.ts

ts
export const HOME_PAGE = RoutesAlias.Dashboard;

路由和菜单类型

ts
export type MenuListType = {
  id: number; // id
  path: string; // 路由路径
  name: string; // 组件名
  component?: string; // 组件路径
  meta: {
    /** 路由标题 */
    title: string;
    /** 路由图标 */
    icon?: string;
    /** 是否显示徽章 */
    showBadge?: boolean;
    /** 文本徽章 */
    showTextBadge?: string;
    /** 是否在菜单中隐藏 */
    isHide?: boolean;
    /** 是否在标签页中隐藏 */
    isHideTab?: boolean;
    /** 外部链接 */
    link?: string;
    /** 是否为iframe */
    isIframe?: boolean;
    /** 是否缓存 */
    keepAlive?: boolean;
    /** 操作权限 */
    authList?: Array<{
      /** 权限名称 */
      title: string;
      /** 权限标识 */
      auth_mark: string;
    }>;
    /** 是否为一级菜单(不需要手动配置,自动识别) */
    isFirstLevel?: boolean;
    /** 角色权限 */
    roles?: string[];
    /** 是否固定标签页 */
    fixedTab?: boolean;
  };
  children?: MenuListType[]; // 子路由
};

meta

meta 是菜单的元数据,用于定义菜单的显示和行为。包含以下属性:

title

  • 类型:string
  • 说明:路由标题

icon

  • 类型:string
  • 说明:路由图标

showBadge

  • 类型:boolean
  • 说明:是否显示徽章

showTextBadge

  • 类型:string
  • 说明:文本徽章

isHide

  • 类型:boolean
  • 说明:是否在菜单中隐藏

isHideTab

  • 类型:boolean
  • 说明:是否在标签页中隐藏
  • 类型:string
  • 说明:外部链接

isIframe

  • 类型:boolean
  • 说明:是否为 iframe

keepAlive

  • 类型:boolean
  • 说明:是否缓存

authList

  • 类型:Array<{title: string, auth_mark: string}>
  • 说明:操作权限列表,包含权限名称和权限标识

isFirstLevel

  • 类型:boolean
  • 说明:是否为一级菜单,不需要手动配置,自动识别

roles

  • 类型:string[]
  • 说明:角色权限

fixedTab

  • 类型:boolean
  • 说明:是否固定标签页

根据 MIT 许可证发布