breadcrumb.vue 4.6 KB

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