路由

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

配置

模块说明

src/router/modules 内的 .ts 文件会被视为一个路由模块。

一个路由模块包含以下结构

  1. import { RouteRecordRaw } from 'vue-router';
  2. import { Layout } from '@/router/constant';
  3. import { DashboardOutlined } from '@vicons/antd';
  4. import { renderIcon } from '@/utils/index';
  5. const routeName = 'dashboard';
  6. const routes: Array<RouteRecordRaw> = [
  7. {
  8. path: '/dashboard',
  9. name: routeName,
  10. redirect: '/dashboard/console',
  11. component: Layout,
  12. meta: {
  13. title: 'Dashboard',
  14. icon: renderIcon(DashboardOutlined),
  15. permissions: ['dashboard_console', 'dashboard_console', 'dashboard_workplace'],
  16. sort: 0,
  17. },
  18. children: [
  19. {
  20. path: 'console',
  21. name: `${routeName}_console`,
  22. meta: {
  23. title: '主控台',
  24. permissions: ['dashboard_console'],
  25. },
  26. component: () => import('@/views/dashboard/console/console.vue'),
  27. },
  28. {
  29. path: 'workplace',
  30. name: `${routeName}_workplace`,
  31. meta: {
  32. title: '工作台',
  33. keepAlive: true,
  34. permissions: ['dashboard_workplace'],
  35. },
  36. component: () => import('@/views/dashboard/workplace/workplace.vue'),
  37. },
  38. ],
  39. },
  40. ];
  41. export default routes;

多级路由

::: warning 注意事项

  • 整个项目所有路由 name 不能重复
  • 除了 layout 对应的 path 前面需要加 /,其余子路由都不要以/开头
  • 多级路由,当没有配置时,redirectredirect 默认为第一个子路由,配置则优先按配置 :::

示例

  1. import { RouteRecordRaw } from 'vue-router';
  2. import { Layout, ParentLayout } from '@/router/constant';
  3. import { WalletOutlined } from '@vicons/antd';
  4. import { renderIcon } from '@/utils/index';
  5. const routeName = 'comp';
  6. const routes: Array<RouteRecordRaw> = [
  7. {
  8. path: '/comp',
  9. name: routeName,
  10. component: Layout,
  11. redirect: '/comp/table',
  12. meta: {
  13. title: '组件示例',
  14. icon: renderIcon(WalletOutlined),
  15. sort: 8,
  16. },
  17. children: [
  18. {
  19. path: 'table',
  20. name: `${routeName}_table`,
  21. redirect: '/comp/table/basic',
  22. component: ParentLayout,
  23. meta: {
  24. title: '表格',
  25. },
  26. children: [
  27. {
  28. path: 'basic',
  29. name: `${routeName}_table_basic`,
  30. meta: {
  31. title: '基础表格',
  32. },
  33. component: () => import('@/views/comp/table/basic.vue'),
  34. },
  35. {
  36. path: 'editCell',
  37. name: `${routeName}_table_editCell`,
  38. meta: {
  39. title: '单元格编辑',
  40. },
  41. component: () => import('@/views/comp/table/editCell.vue'),
  42. },
  43. {
  44. path: 'editRow',
  45. name: `${routeName}_table_editRow`,
  46. meta: {
  47. title: '整行编辑',
  48. },
  49. component: () => import('@/views/comp/table/editRow.vue'),
  50. },
  51. ],
  52. },
  53. {
  54. path: 'upload',
  55. name: `${routeName}_upload`,
  56. meta: {
  57. title: '上传',
  58. },
  59. component: () => import('@/views/comp/upload/index.vue'),
  60. },
  61. ],
  62. },
  63. ];
  64. export default routes;

Meta 配置说明

  1. export interface RouteMeta {
  2. //菜单名称 一般必填
  3. title: string;
  4. //禁用菜单
  5. disabled:boolean;
  6. //菜单图标
  7. icon: VNode;
  8. //缓存该路由
  9. keepAlive: boolean;
  10. //隐藏菜单
  11. hidden: boolean;
  12. //排序越小越排前
  13. sort: number;
  14. //取消自动计算根路由模式
  15. alwaysShow: boolean
  16. // 当路由设置了该属性,则会高亮相对应的侧边栏。
  17. // 这在某些场景非常有用,比如:一个列表页路由为:/list/basic-list
  18. // 点击进入详情页,这时候路由为/list/basic-info/1,但你想在侧边栏高亮列表的路由,就可以进行如下设置
  19. // 注意是配置高亮路由 `name`,不是path
  20. activeMenu: string;
  21. //是否跟路由 顶部混合菜单,必须传 true,否则左侧会显示异常(场景就是,分割菜单之后,当一级菜单没有子菜单)
  22. isRoot: boolean;
  23. //内联外部地址
  24. frameSrc: string;
  25. //菜单包含权限集合,满足其中一个就会显示
  26. permissions: string[];
  27. //是否固定 设置为 true 之后 多页签不可删除
  28. affix: boolean
  29. }

图标

为了简化使用,只需用renderIcon(WalletOutlined)方法,传入 xicons 中图标即可

新增路由

如何新增一个路由模块

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

示例,新增 test.ts 文件

  1. import { RouteRecordRaw } from 'vue-router';
  2. import { Layout } from '@/router/constant';
  3. import { CheckCircleOutlined } from '@vicons/antd';
  4. import { renderIcon } from '@/utils/index';
  5. const routes: Array<RouteRecordRaw> = [
  6. {
  7. path: '/result',
  8. name: 'Result',
  9. redirect: '/result/success',
  10. component: Layout,
  11. meta: {
  12. title: '结果页面',
  13. icon: renderIcon(CheckCircleOutlined),
  14. sort: 4,
  15. },
  16. children: [
  17. {
  18. path: 'success',
  19. name: 'result-success',
  20. meta: {
  21. title: '成功页',
  22. },
  23. component: () => import('@/views/result/success.vue'),
  24. },
  25. ],
  26. },
  27. ];
  28. export default routes;

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

验证

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

路由刷新

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

实现

  1. import { useRoute } from 'vue-router';
  2. const route = useRoute();
  3. router.push({
  4. path: '/redirect' + unref(route).fullPath,
  5. });

Redirect

src/views/redirect/index.vue

  1. import { defineComponent, onBeforeMount } from 'vue';
  2. import { useRoute, useRouter } from 'vue-router';
  3. import { NEmpty } from 'naive-ui';
  4. export default defineComponent({
  5. name: 'Redirect',
  6. setup() {
  7. const route = useRoute();
  8. const router = useRouter();
  9. onBeforeMount(() => {
  10. const { params, query } = route;
  11. const { path } = params;
  12. router.replace({
  13. path: '/' + (Array.isArray(path) ? path.join('/') : path),
  14. query,
  15. });
  16. });
  17. return () => <NEmpty />;
  18. },
  19. });

外联

在侧边栏中配置一个外链,只要你在 name 中填写了合法的 url 路径,当你点击侧边栏的时候就会帮你新开这个页面。

  1. {
  2. path: '/external',
  3. name: 'https://jekip.github.io/docs/',
  4. meta: {
  5. title: '文档地址',
  6. icon: renderIcon(CheckCircleOutlined),
  7. sort: 4,
  8. }
  9. }

::: warning 注意事项

  • path 不能为链接,必须为 / 开头字符串
  • 子路由都不要以/开头,跳转外部地址,只需把 name 填写完整网址即可 :::

内联

在侧边栏中配置一个内联外部地址,只要你在 meta.frameSrc 填写了合法的 url 路径,当你点击侧边栏的时候就会帮你内联显示这个页面。

  1. import { RouteRecordRaw } from 'vue-router';
  2. import { Layout } from '@/router/constant';
  3. import { DesktopOutline } from '@vicons/ionicons5';
  4. import { renderIcon } from '@/utils/index';
  5. const IFrame = () => import('@/views/iframe/index.vue');
  6. const routes: Array<RouteRecordRaw> = [
  7. {
  8. path: '/frame',
  9. name: 'Frame',
  10. redirect: '/frame/docs',
  11. component: Layout,
  12. meta: {
  13. title: '外部页面',
  14. sort: 9,
  15. icon: renderIcon(DesktopOutline),
  16. },
  17. children: [
  18. {
  19. path: 'docs',
  20. name: 'frame-docs',
  21. meta: {
  22. title: '项目文档(内嵌)',
  23. frameSrc: 'https://naive-ui-admin-docs.vercel.app',
  24. },
  25. component: IFrame,
  26. },
  27. {
  28. path: 'naive',
  29. name: 'frame-naive',
  30. meta: {
  31. title: 'NaiveUi(内嵌)',
  32. frameSrc: 'https://www.naiveui.com',
  33. },
  34. component: IFrame,
  35. },
  36. ],
  37. },
  38. ];
  39. export default routes;

根路由

系统已经帮你做了判断,当一个路由下面的 children 声明的路由大于>1 个时,自动会变成嵌套的模式。 如果子路由正好等于一个就会默认将子路由作为根路由显示在侧边栏中,若不想这样,可以通过设置在根路由meta中设置alwaysShow: true来取消这一特性

  1. {
  2. path: '/external',
  3. name: 'external',
  4. component: Layout,
  5. meta: {
  6. sort: 4, //排序依然还是在这里定义
  7. },
  8. children: [
  9. {
  10. path: 'console',
  11. name: `console`,
  12. meta: {
  13. title: '主控台',
  14. permission: ['dashboard_console'],
  15. },
  16. component: () => import('@/views/dashboard/console/console.vue'),
  17. }
  18. ]
  19. }

如何开启单个页面缓存

开启缓存有 3 个条件

  1. 在router中meta内将keepAlive 设置为 true
  2. 路由设置 name,且不能重复
  3. 路由对应的组件加上 name,与路由设置的 name 保持一致
  1. {
  2. ...,
  3. // name
  4. name: 'Login',
  5. // 对应组件组件的name
  6. component: () => import('@/views/login/index.vue'),
  7. ...
  8. },
  9. // @/views/login/index.vue
  10. export default defineComponent({
  11. // 需要和路由的name一致
  12. name:"Login"
  13. });

:::warning 注意

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

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