SidebarItem.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <script setup lang="ts">
  2. import path from 'path-browserify';
  3. import { isExternal } from '@/utils/index';
  4. import AppLink from './Link.vue';
  5. import SvgIcon from '@/components/SvgIcon/index.vue';
  6. const props = defineProps({
  7. /**
  8. * 路由(eg:level_3_1)
  9. */
  10. item: {
  11. type: Object,
  12. required: true
  13. },
  14. /**
  15. * 父层级完整路由路径(eg:/level/level_3/level_3_1)
  16. */
  17. basePath: {
  18. type: String,
  19. required: true
  20. }
  21. });
  22. const onlyOneChild = ref(); // 临时变量,唯一子路由
  23. /**
  24. * 判断当前路由是否只有一个子路由
  25. *
  26. * 1:如果只有一个子路由: 返回 true
  27. * 2:如果无子路由 :返回 true
  28. *
  29. * @param children 子路由数组
  30. * @param parent 当前路由
  31. */
  32. function hasOneShowingChild(children = [], parent: any) {
  33. // 需要显示的子路由数组
  34. const showingChildren = children.filter((item: any) => {
  35. if (item.meta?.hidden) {
  36. return false; // 过滤不显示的子路由
  37. } else {
  38. onlyOneChild.value = item; // 唯一子路由赋值(多个子路由情况 onlyOneChild 变量是用不上的)
  39. return true;
  40. }
  41. });
  42. // 1:如果只有一个子路由, 返回 true
  43. if (showingChildren.length === 1) {
  44. return true;
  45. }
  46. // 2:如果无子路由, 复制当前路由信息作为其子路由,满足只拥有一个子路由的条件,所以返回 true
  47. if (showingChildren.length === 0) {
  48. onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
  49. return true;
  50. }
  51. return false;
  52. }
  53. /**
  54. * 解析路径
  55. *
  56. * @param routePath 路由路径
  57. */
  58. function resolvePath(routePath: string) {
  59. if (isExternal(routePath)) {
  60. return routePath;
  61. }
  62. if (isExternal(props.basePath)) {
  63. return props.basePath;
  64. }
  65. // 完整路径 = 父级路径(/level/level_3) + 路由路径
  66. const fullPath = path.resolve(props.basePath, routePath); // 相对路径 → 绝对路径
  67. return fullPath;
  68. }
  69. </script>
  70. <template>
  71. <div v-if="!item.meta || !item.meta.hidden">
  72. <!-- 只包含一个子路由节点的路由,显示其【唯一子路由】 -->
  73. <template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren)">
  74. <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
  75. <el-menu-item :index="resolvePath(onlyOneChild.path)">
  76. <svg-icon v-if="onlyOneChild.meta && onlyOneChild.meta.icon" :icon-class="onlyOneChild.meta.icon"
  77. />
  78. <template #title>
  79. {{ onlyOneChild.meta.title }}
  80. </template>
  81. </el-menu-item>
  82. </app-link>
  83. </template>
  84. <!-- 包含多个子路由 -->
  85. <el-sub-menu v-else :index="resolvePath(item.path)" teleported>
  86. <template #title>
  87. <svg-icon
  88. v-if="item.meta && item.meta.icon"
  89. :icon-class="item.meta.icon"
  90. />
  91. <span v-if="item.meta && item.meta.title">{{item.meta.title }}</span>
  92. </template>
  93. <sidebar-item
  94. v-for="child in item.children"
  95. :key="child.path"
  96. :item="child"
  97. :base-path="resolvePath(child.path)"
  98. />
  99. </el-sub-menu>
  100. </div>
  101. </template>