Skip to content
当前页

路由

项目路由配置存放于 src/router/routers 下面。 src/router/routers/modules用于存放路由模块,在该目录下的文件会自动注册。

模块说明

路由分为前端本地路由和后端返回路由,前端本地路由配置在 src/router/routers/modules 内的 .ts 文件会被视为一个路由模块。

项目登录后后端返回的路由和前端写死的路由会进行合并,最终组成整个路由结构。按照配置中的排序字段来进行排序。

RouteMeta 配置说明

ts
export interface RouteMeta {
  // 路由title  一般必填
  title: string;
  // 动态路由可打开Tab页数
  dynamicLevel?: number;
  // 动态路由的实际Path, 即去除路由的动态部分;
  realPath?: string;
  // 是否忽略权限,只在权限模式为Role的时候有效
  ignoreAuth?: boolean;
  // 可以访问的角色,只在权限模式为Role的时候有效
  roles?: RoleEnum[];
  // 是否忽略KeepAlive缓存
  ignoreKeepAlive?: boolean;
  // 是否固定标签
  affix?: boolean;
  // 图标,也是菜单图标
  icon?: string;
  // 内嵌iframe的地址
  frameSrc?: string;
  // 指定该路由切换的动画名
  transitionName?: string;
  // 隐藏该路由在面包屑上面的显示
  hideBreadcrumb?: boolean;
  // 如果该路由会携带参数,且需要在tab页上面显示。则需要设置为true
  carryParam?: boolean;
  // 隐藏所有子菜单
  hideChildrenInMenu?: boolean;
  // 当前激活的菜单。用于配置详情页时左侧激活的菜单路径
  currentActiveMenu?: string;
  // 当前路由不再标签页显示
  hideTab?: boolean;
  // 当前路由不再菜单显示
  hideMenu?: boolean;
  // 菜单排序,只对第一级有效
  orderNo?: number;
  // 忽略路由。用于在ROUTE_MAPPING以及BACK权限模式下,生成对应的菜单而忽略路由。2.5.3以上版本有效
  ignoreRoute?: boolean;
  // 是否在子级菜单的完整path中忽略本级path。2.5.3以上版本有效
  hidePathForChildren?: boolean;
}

前端路由配置结构

一个前端本地路由模块包含以下结构:

ts
import type { AppRouteRecordRaw } from "/@/router/Types";
import { LAYOUT } from "/@/router/Constant";
import { t } from "/@/hooks/web/UseI18n";

const flows: AppRouteRecordRaw = {
    path: "/flow",
    name: "FlowDemo",
    component: LAYOUT,
    redirect: "/flow/flowChart",
    meta: {
        menuSort: 18,
        icon: "tabler:chart-dots",
        title: t("routes.demo.flow.name")
    },
    children: [
        {
            path: "flowChart",
            name: "flowChartDemo",
            component: () => import("/@/views/demo/flow-chart/index.vue"),
            meta: {
                title: t("routes.demo.flow.flowChart")
            }
        }
    ]
};

export default flows;

多级路由

注意事项

  • 整个项目所有路由 name 不能重复
  • 所有的多级路由最终都会转成二级路由,所以不能内嵌子路由
  • 除了 layout 对应的 path 前面需要加 /,其余子路由都不要以/开头

示例

ts
import { AppRouteRecordRaw } from "/@/router/Types";
import { LAYOUT } from "/@/router/Constant";

const moreLevel: AppRouteRecordRaw = {
    name: "多级目录",
    path: "/test",
    component: LAYOUT,
    meta: {
        title: "多级目录",
        icon: "ion:folder-open-outline",
        hideMenu: false,
        menuSort: 10
    },
    children: [
        {
            name: "目录1",
            path: "menu1",
            meta: {
                title: "目录1",
                icon: "ion:folder-open-outline",
                hideMenu: false,
                menuSort: 1
            },
            children: [{
                path: "/test/test1/test2",
                name: "目录2",
                meta: {
                    title: "目录2",
                    icon: "ion:folder-open-outline",
                    hideMenu: false,
                    menuSort: 1
                },
                children: [
                    {
                        path: "/test/test1/test2/test3",
                        name: "多级菜单",
                        meta: {
                            title: "多级菜单",
                            icon: "ant-design:appstore-outlined",
                            hideMenu: false,
                            menuSort: 1,
                            ignoreKeepAlive: false
                        },
                        component: () => import("/@/views/demo/flow-chart/index.vue")
                    }
                ]
            }]
        }
    ],
    redirect: "/test/test1/test2/test3"
};
export default moreLevel;

外部页面嵌套

只需要将 frameSrc 设置为需要跳转的地址即可

ts
const IFrame = () => import('/@/views/sys/iframe/FrameBlank.vue');

const Frame: AppRouteRecordRaw = {
    path: "doc",
    name: "Doc",
    component: IFrame,
    meta: {
        frameSrc: "http://www.mfish.com.cn/",
        title: t("routes.demo.iframe.doc")
    }
}

外链

只需要将 path 设置为需要跳转的HTTP 地址即可

ts
{
    name: "1ce2ac44228e37c063e9cd55ed8f0a49",
    path: "https://github.com/mfish-qf/mfish-nocode",
    meta: {
        title: "Git地址",
        icon: "ion:logo-github",
        hideMenu: false,
        menuSort: 2,
        ignoreKeepAlive: false,
        frameSrc: "https://github.com/mfish-qf/mfish-nocode"
    }
}

动态路由Tab自动关闭功能

若需要开启该功能,需要在动态路由的meta中设置如下两个参数:

  • dynamicLevel 最大能打开的Tab标签页数
  • realPath 动态路由实际路径(考虑到动态路由有时候可能存在N层的情况, 例:/:id/:subId/:...), 为了减少计算开销, 使用配置方式事先规定好路由的实际路径(注意: 该参数若不设置,将无法使用该功能)
ts
{
  path: 'detail/:id',
  name: 'TabDetail',
  component: () => import('/@/views/demo/feat/tabs/TabDetail.vue'),
  meta: {
    currentActiveMenu: '/feat/tabs',
    title: t('routes.demo.feat.tabDetail'),
    hideMenu: true,
    dynamicLevel: 3,
    realPath: '/feat/tabs/detail',
  },
}

新增前端本地路由

  1. src/router/routes/modules 内新增一个模块文件。

示例,新增 flows.ts 文件

ts
import type { AppRouteRecordRaw } from "/@/router/Types";
import { LAYOUT } from "/@/router/Constant";
import { t } from "/@/hooks/web/UseI18n";

const flows: AppRouteRecordRaw = {
    path: "/flow",
    name: "FlowDemo",
    component: LAYOUT,
    redirect: "/flow/flowChart",
    meta: {
        menuSort: 18,
        icon: "tabler:chart-dots",
        title: t("routes.demo.flow.name")
    },
    children: [
        {
            path: "flowChart",
            name: "flowChartDemo",
            component: () => import("/@/views/demo/flow-chart/index.vue"),
            meta: {
                title: t("routes.demo.flow.flowChart")
            }
        }
    ]
};

export default flows;

新增后端路由

多级菜单

外部页面嵌套

外链

带参菜单

此时路由已添加完成,不需要手动引入,放在src/router/routes/modules 内的文件会自动被加载。

验证

访问 ip:端口/about/index 出现对应组件内容即代表成功

路由刷新

项目中采用的是重定向方式

实现

ts
import { useRedo } from '/@/hooks/web/UsePage';
import { defineComponent } from 'vue';
export default defineComponent({
  setup() {
    const redo = useRedo();
    // 执行刷新
    redo();
    return {};
  },
});

Redirect

src/views/sys/redirect/index.vue

ts
import { defineComponent, unref } from 'vue';
import { useRouter } from 'vue-router';
export default defineComponent({
  name: 'Redirect',
  setup() {
    const { currentRoute, replace } = useRouter();
    const { params, query } = unref(currentRoute);
    const { path } = params;
    const _path = Array.isArray(path) ? path.join('/') : path;
    replace({
      path: '/' + _path,
      query,
    });
    return {};
  },
});

页面跳转

页面跳转建议采用项目提供的 useGo

方式

ts
import { useGo } from '/@/hooks/web/usePage';
import { defineComponent } from 'vue';
export default defineComponent({
  setup() {
    const go = useGo();

    // 执行刷新
    go();
    go(PageEnum.Home);
    return {};
  },
});

多标签页

标签页使用的是 keep-aliverouter-view 实现,实现切换 tab 后还能保存切换之前的状态。

如何开启页面缓存

开启缓存有 3 个条件

  1. src/settings/ProjectSetting.ts 内将openKeepAlive 设置为 true
  2. 路由设置 name,且不能重复
  3. 路由对应的组件加上 name,与路由设置的 name 保持一致
ts
{
   ...,
    // name
    name: 'Login',
    // 对应组件组件的name
    component: () => import('/@/views/sys/login/index.vue'),
    ...
  },

  // /@/views/sys/login/index.vue
  export default defineComponent({
    // 需要和路由的name一致
    name:"Login"
  });

注意

keep-alive 生效的前提是:需要将路由的 name 属性及对应的页面的 name 设置成一样。因为:

include - 字符串或正则表达式,只有名称匹配的组件会被缓存

如何让某个页面不缓存

可在 router.meta 下配置

可以将 ignoreKeepAlive 配置成 true 即可关闭缓存。

ts
export interface RouteMeta {
  // 是否忽略KeepAlive缓存
  ignoreKeepAlive?: boolean;
}

如何更改首页路由

首页路由指的是应用程序中的默认路由,默认指向所有路由中排序第一的路由,并且该路由在Tab上是固定的,即使设置affix: false也不允许关闭。

例:首页路由配置的是/dashboard/analysis,那么当直接访问 http://localhost:5281/ 会自动跳转到http://localhost:5281/#/dashboard/analysis 上(用户已登录的情况下)

修改方法

如果需要修改,请将首页配置排序放在最前面