Skip to content

Commit

Permalink
feat(projects): 面包屑
Browse files Browse the repository at this point in the history
  • Loading branch information
Soybean committed Jan 11, 2022
1 parent e25afe2 commit 09c7658
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 10 deletions.
13 changes: 12 additions & 1 deletion src/interface/system.ts
@@ -1,7 +1,18 @@
import type { MenuOption } from 'naive-ui';
import type { MenuOption, DropdownOption } from 'naive-ui';

/** 菜单项配置 */
export type GlobalMenuOption = MenuOption & {
routeName: string;
routePath: string;
};

/** 面包屑 */
export type GlobalBreadcrumb = DropdownOption & {
key: string;
label: string;
disabled: boolean;
routeName: string;
hasChildren: boolean;
iconName?: string;
children?: GlobalBreadcrumb[];
};
43 changes: 43 additions & 0 deletions src/layouts/common/GlobalHeader/components/GlobalBreadcrumb.vue
@@ -0,0 +1,43 @@
<template>
<n-breadcrumb class="px-12px">
<template v-for="breadcrumb in breadcrumbs" :key="breadcrumb.key">
<n-breadcrumb-item>
<n-dropdown v-if="breadcrumb.hasChildren" :options="breadcrumb.children" @select="dropdownSelect">
<span>
<component :is="breadcrumb.icon" v-if="theme.header.crumb.showIcon" class="inline-block mr-4px text-16px" />
<span>{{ breadcrumb.label }}</span>
</span>
</n-dropdown>
<template v-else>
<component :is="breadcrumb.icon" v-if="theme.header.crumb.showIcon" class="inline-block mr-4px text-16px" />
<span>{{ breadcrumb.label }}</span>
</template>
</n-breadcrumb-item>
</template>
</n-breadcrumb>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { NBreadcrumb, NBreadcrumbItem, NDropdown } from 'naive-ui';
import { routePath } from '@/router';
import { useThemeStore, useRouteStore } from '@/store';
import { useRouterPush } from '@/composables';
import { getBreadcrumbByRouteKey } from '@/utils';
import type { GlobalMenuOption } from '@/interface';
const route = useRoute();
const theme = useThemeStore();
const routeStore = useRouteStore();
const { routerPush } = useRouterPush();
const breadcrumbs = computed(() =>
getBreadcrumbByRouteKey(route.name as string, routeStore.menus as GlobalMenuOption[], routePath('root'))
);
function dropdownSelect(key: string) {
routerPush({ name: key });
}
</script>
<style scoped></style>
26 changes: 26 additions & 0 deletions src/layouts/common/GlobalHeader/components/HeaderMenu.vue
@@ -0,0 +1,26 @@
<template>
<n-menu :value="activeKey" mode="horizontal" :options="menus" @update:value="handleUpdateMenu" />
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { NMenu } from 'naive-ui';
import type { MenuOption } from 'naive-ui';
import { useRouteStore } from '@/store';
import { useRouterPush } from '@/composables';
import type { GlobalMenuOption } from '@/interface';
const route = useRoute();
const routeStore = useRouteStore();
const { routerPush } = useRouterPush();
const menus = computed(() => routeStore.menus as GlobalMenuOption[]);
const activeKey = computed(() => route.name as string);
function handleUpdateMenu(_key: string, item: MenuOption) {
const menuItem = item as GlobalMenuOption;
routerPush(menuItem.routePath);
}
</script>
<style scoped></style>
4 changes: 3 additions & 1 deletion src/layouts/common/GlobalHeader/components/index.ts
@@ -1,7 +1,9 @@
import MenuCollapse from './MenuCollapse.vue';
import GlobalBreadcrumb from './GlobalBreadcrumb.vue';
import HeaderMenu from './HeaderMenu.vue';
import GithubSite from './GithubSite.vue';
import FullScreen from './FullScreen.vue';
import ThemeMode from './ThemeMode.vue';
import UserAvatar from './UserAvatar.vue';

export { MenuCollapse, GithubSite, FullScreen, ThemeMode, UserAvatar };
export { MenuCollapse, GlobalBreadcrumb, HeaderMenu, GithubSite, FullScreen, ThemeMode, UserAvatar };
20 changes: 13 additions & 7 deletions src/layouts/common/GlobalHeader/index.vue
Expand Up @@ -3,13 +3,11 @@
<global-logo v-if="showLogo" :show-title="true" class="h-full" :style="{ width: theme.sider.width + 'px' }" />
<div v-if="!showHeaderMenu" class="flex-1-hidden flex-y-center h-full">
<menu-collapse v-if="showMenuCollape" />
<!-- <global-breadcrumb v-if="theme.header.crumb.visible" /> -->
<global-breadcrumb v-if="theme.header.crumb.visible" />
</div>
<div v-else class="flex-1-hidden flex-y-center h-full" :style="{ justifyContent: theme.menu.horizontalPosition }">
<header-menu />
</div>
<div
v-else
class="flex-1-hidden flex-y-center h-full"
:style="{ justifyContent: theme.menu.horizontalPosition }"
></div>
<div class="flex justify-end h-full">
<github-site />
<full-screen />
Expand All @@ -24,7 +22,15 @@ import { DarkModeContainer } from '@/components';
import { useThemeStore } from '@/store';
import type { GlobalHeaderProps } from '@/interface';
import GlobalLogo from '../GlobalLogo/index.vue';
import { MenuCollapse, GithubSite, FullScreen, ThemeMode, UserAvatar } from './components';
import {
MenuCollapse,
GlobalBreadcrumb,
HeaderMenu,
GithubSite,
FullScreen,
ThemeMode,
UserAvatar
} from './components';
interface Props {
/** 显示logo */
Expand Down
2 changes: 1 addition & 1 deletion src/router/routes/index.ts
Expand Up @@ -54,7 +54,7 @@ export const constantRoutes: AuthRoute.Route[] = [
singleLayout: 'blank'
}
},
// 匹配无效的路径重定向not-found的页面
// 匹配无效路径的路由
{
name: 'not-found-page',
path: '/:pathMatch(.*)*',
Expand Down
35 changes: 35 additions & 0 deletions src/utils/router/breadcrumb.ts
@@ -0,0 +1,35 @@
import type { GlobalMenuOption, GlobalBreadcrumb } from '@/interface';

/**
* 获取面包屑数据
* @param activeKey - 当前页面路由的key
* @param menus - 菜单数据
* @param rootPath - 根路由路径
*/
export function getBreadcrumbByRouteKey(activeKey: string, menus: GlobalMenuOption[], rootPath: string) {
return menus.map(menu => getBreadcrumbItem(activeKey, menu, rootPath)).flat(1);
}

function getBreadcrumbItem(activeKey: string, menu: GlobalMenuOption, rootPath: string) {
const list: GlobalBreadcrumb[] = [];
if (activeKey.includes(menu.routeName)) {
const breadcrumb: GlobalBreadcrumb = {
key: menu.routeName,
label: menu.label as string,
routeName: menu.routeName,
disabled: menu.routePath === rootPath,
hasChildren: false
};
if (menu.icon) {
breadcrumb.icon = menu.icon;
}
if (menu.children && menu.children.length) {
breadcrumb.hasChildren = true;
breadcrumb.children = menu.children
.map(item => getBreadcrumbItem(activeKey, item as GlobalMenuOption, rootPath))
.flat(1);
}
list.push(breadcrumb);
}
return list;
}
1 change: 1 addition & 0 deletions src/utils/router/index.ts
@@ -1,3 +1,4 @@
export * from './helpers';
export * from './menu';
export * from './breadcrumb';
export * from './regexp';

0 comments on commit 09c7658

Please sign in to comment.