breadcrumb.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <template>
  2. <div v-if="isShowBreadcrumb" class="layout-navbars-breadcrumb">
  3. <SvgIcon
  4. :name="themeConfig.isCollapse ? 'ele-Expand' : 'ele-Fold'"
  5. :size="16"
  6. class="layout-navbars-breadcrumb-icon"
  7. @click="onThemeConfigChange"
  8. />
  9. <el-breadcrumb class="layout-navbars-breadcrumb-hide">
  10. <transition-group name="breadcrumb">
  11. <el-breadcrumb-item v-for="(v, k) in state.breadcrumbList"
  12. :key="!v.meta.tagsViewName ? v.meta.title : v.meta.tagsViewName">
  13. <span v-if="k === state.breadcrumbList.length - 1" class="layout-navbars-breadcrumb-span">
  14. <SvgIcon v-if="themeConfig.isBreadcrumbIcon" :name="v.meta.icon"
  15. class="layout-navbars-breadcrumb-iconfont"/>
  16. <div v-if="!v.meta.tagsViewName">{{ $t(v.meta.title) }}</div>
  17. <div v-else>{{ v.meta.tagsViewName }}</div>
  18. </span>
  19. <a v-else @click.prevent="onBreadcrumbClick(v)" class="flex">
  20. <SvgIcon v-if="themeConfig.isBreadcrumbIcon" :name="v.meta.icon"
  21. class="layout-navbars-breadcrumb-iconfont"/>
  22. <span >
  23. {{ $t(v.meta.title) }}
  24. </span>
  25. </a>
  26. </el-breadcrumb-item>
  27. </transition-group>
  28. </el-breadcrumb>
  29. </div>
  30. </template>
  31. <script lang="ts" name="layoutBreadcrumb" setup>
  32. import { reactive, computed, onMounted } from 'vue';
  33. import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
  34. import { Local } from '/@/utils/storage';
  35. import other from '/@/utils/other';
  36. import { storeToRefs } from 'pinia';
  37. import { useThemeConfig } from '/@/stores/themeConfig';
  38. import { useRoutesList } from '/@/stores/routesList';
  39. // 定义变量内容
  40. const stores = useRoutesList();
  41. const storesThemeConfig = useThemeConfig();
  42. const { themeConfig } = storeToRefs(storesThemeConfig);
  43. const { routesList } = storeToRefs(stores);
  44. const route = useRoute();
  45. const router = useRouter();
  46. const state = reactive<BreadcrumbState>({
  47. breadcrumbList: [],
  48. routeSplit: [],
  49. routeSplitFirst: '',
  50. routeSplitIndex: 1
  51. });
  52. // 动态设置经典、横向布局不显示
  53. const isShowBreadcrumb = computed(() => {
  54. initRouteSplit(route.path);
  55. const { layout, isBreadcrumb } = themeConfig.value;
  56. if (layout === 'classic' || layout === 'transverse') return false;
  57. else return isBreadcrumb ? true : false;
  58. });
  59. // 面包屑点击时
  60. const onBreadcrumbClick = (v: RouteItem) => {
  61. const { redirect, path } = v;
  62. if (redirect) router.push(redirect);
  63. else router.push(path);
  64. };
  65. // 展开/收起左侧菜单点击
  66. const onThemeConfigChange = () => {
  67. themeConfig.value.isCollapse = !themeConfig.value.isCollapse;
  68. setLocalThemeConfig();
  69. };
  70. // 存储布局配置
  71. const setLocalThemeConfig = () => {
  72. Local.remove('themeConfig');
  73. Local.set('themeConfig', themeConfig.value);
  74. };
  75. // 处理面包屑数据
  76. const getBreadcrumbList = (arr: RouteItems) => {
  77. arr.forEach((item: RouteItem) => {
  78. state.routeSplit.forEach((v: string, k: number, arrs: string[]) => {
  79. if (state.routeSplitFirst === item.path) {
  80. state.routeSplitFirst += `/${ arrs[state.routeSplitIndex] }`;
  81. state.breadcrumbList.push(item);
  82. state.routeSplitIndex++;
  83. if (item.children) getBreadcrumbList(item.children);
  84. }
  85. });
  86. });
  87. };
  88. // 当前路由字符串切割成数组,并删除第一项空内容
  89. const initRouteSplit = (path: string) => {
  90. if (!themeConfig.value.isBreadcrumb) return false;
  91. state.breadcrumbList = [ routesList.value[0] ];
  92. state.routeSplit = path.split('/');
  93. state.routeSplit.shift();
  94. state.routeSplitFirst = `/${ state.routeSplit[0] }`;
  95. state.routeSplitIndex = 1;
  96. getBreadcrumbList(routesList.value);
  97. if (route.name === 'home' || (route.name === 'notFound' && state.breadcrumbList.length > 1)) state.breadcrumbList.shift();
  98. if (state.breadcrumbList.length > 0)
  99. state.breadcrumbList[state.breadcrumbList.length - 1].meta.tagsViewName = other.setTagsViewNameI18n(<RouteToFrom>route);
  100. };
  101. // 页面加载时
  102. onMounted(() => {
  103. initRouteSplit(route.path);
  104. });
  105. // 路由更新时
  106. onBeforeRouteUpdate((to) => {
  107. initRouteSplit(to.path);
  108. });
  109. </script>
  110. <style lang="scss" scoped>
  111. .layout-navbars-breadcrumb {
  112. flex: 1;
  113. height: inherit;
  114. display: flex;
  115. align-items: center;
  116. .layout-navbars-breadcrumb-icon {
  117. cursor: pointer;
  118. font-size: 18px;
  119. color: var(--next-bg-topBarColor);
  120. height: 100%;
  121. width: 40px;
  122. opacity: 0.8;
  123. &:hover {
  124. opacity: 1;
  125. }
  126. }
  127. .layout-navbars-breadcrumb-span {
  128. display: flex;
  129. opacity: 0.7;
  130. color: var(--next-bg-topBarColor);
  131. }
  132. .layout-navbars-breadcrumb-iconfont {
  133. font-size: 14px;
  134. margin-right: 5px;
  135. }
  136. :deep(.el-breadcrumb__separator) {
  137. opacity: 0.7;
  138. color: var(--next-bg-topBarColor);
  139. }
  140. :deep(.el-breadcrumb__inner a, .el-breadcrumb__inner.is-link) {
  141. font-weight: unset !important;
  142. color: var(--next-bg-topBarColor);
  143. &:hover {
  144. color: var(--el-color-primary) !important;
  145. }
  146. }
  147. }
  148. </style>