feat(projects): 新增顶部菜单

This commit is contained in:
Soybean 2021-09-23 00:15:19 +08:00
parent e9db67ee12
commit 221d2cc02d
10 changed files with 102 additions and 29 deletions

View File

@ -1,5 +1,5 @@
export { ContentType, EnumDataType, EnumLoginModule } from './common';
export { EnumAnimate } from './animate';
export { EnumNavMode, EnumNavTheme, EnumMultiTabMode } from './theme';
export { EnumNavMode, EnumNavTheme, EnumMultiTabMode, EnumHorizontalMenuPosition } from './theme';
export { EnumRoutePath, EnumRouteTitle } from './route';
export { EnumStorageKey } from './storage';

View File

@ -13,7 +13,15 @@ export enum EnumNavTheme {
'header-dark' = '暗色的侧边栏和顶栏'
}
/** 多页签风格 */
export enum EnumMultiTabMode {
'button' = '按钮风格',
'browser' = '浏览器风格'
}
/** 水平模式的菜单位置 */
export enum EnumHorizontalMenuPosition {
'flex-start' = '居左',
'center' = '居中',
'flex-end' = '居右'
}

View File

@ -1,3 +1,3 @@
export { UserInfo } from './business';
export { ThemeSettings, NavMode, MultiTabMode, AnimateType } from './theme';
export { ThemeSettings, NavMode, MultiTabMode, AnimateType, HorizontalMenuPosition } from './theme';
export { CustomRoute, RoutePathKey, GlobalMenuOption, LoginModuleType } from './common';

View File

@ -1,4 +1,4 @@
import { EnumAnimate, EnumNavMode, EnumNavTheme, EnumMultiTabMode } from '@/enum';
import { EnumAnimate, EnumNavMode, EnumNavTheme, EnumMultiTabMode, EnumHorizontalMenuPosition } from '@/enum';
export interface ThemeSettings {
/** 深色模式 */
@ -56,6 +56,13 @@ interface HeaderStyle {
bgColor: string;
}
export type HorizontalMenuPosition = keyof typeof EnumHorizontalMenuPosition;
interface HorizontalMenuPositionList {
value: HorizontalMenuPosition;
label: EnumHorizontalMenuPosition;
}
interface MenuStyle {
/** 菜单宽度 */
width: number;
@ -67,6 +74,10 @@ interface MenuStyle {
fixed: boolean;
/** 分割菜单 */
splitMenu: boolean;
/** 水平模式的菜单的位置 */
horizontalPosition: HorizontalMenuPosition;
/** 水平模式的菜单的位置列表 */
horizontalPositionList: HorizontalMenuPositionList[];
}
export type MultiTabMode = keyof typeof EnumMultiTabMode;

View File

@ -0,0 +1,27 @@
<template>
<n-menu :value="activeKey" mode="horizontal" :options="menus" @update:value="handleUpdateMenu" />
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import type { MenuOption } from 'naive-ui';
import { NMenu } from 'naive-ui';
import { menus } from '@/router';
import { GlobalMenuOption } from '@/interface';
const router = useRouter();
const route = useRoute();
const activeKey = computed(() => getActiveKey());
function getActiveKey() {
return route.name as string;
}
function handleUpdateMenu(key: string, item: MenuOption) {
const menuItem = item as GlobalMenuOption;
router.push(menuItem.routePath);
}
</script>
<style scoped></style>

View File

@ -5,11 +5,12 @@
<div v-if="!theme.isVerticalNav" class="menu-width h-full">
<global-logo />
</div>
<div class="flex-y-center h-full">
<div class="flex-1-hidden flex-y-center h-full" :style="{ justifyContent: theme.menuStyle.horizontalPosition }">
<menu-collapse v-if="theme.navStyle.mode !== 'horizontal'" />
<global-breadcrumb v-if="theme.crumbsStyle.visible" />
<global-breadcrumb v-if="theme.crumbsStyle.visible && theme.navStyle.mode !== 'horizontal'" />
<header-menu v-if="theme.navStyle.mode === 'horizontal'" />
</div>
<div class="flex-1 flex justify-end h-full">
<div class="flex justify-end h-full">
<gihub-site />
<full-screen />
<user-avatar />
@ -25,6 +26,7 @@ import { NLayoutHeader } from 'naive-ui';
import { useThemeStore } from '@/store';
import { GlobalBreadcrumb, UserAvatar, MenuCollapse, FullScreen, GihubSite, SettingDrawerButton } from './components';
import { GlobalLogo } from '../common';
import HeaderMenu from './components/HeaderMenu.vue';
defineProps({
zIndex: {

View File

@ -4,25 +4,13 @@
<setting-menu-item label="分割菜单">
<n-switch :value="theme.menuStyle.splitMenu" @update:value="handleSplitMenu" />
</setting-menu-item>
<setting-menu-item label="固定头部和多页签">
<n-switch :value="splitMenu" :disabled="disabledSplitMenu" @update:value="handleFixedHeaderAndTab" />
</setting-menu-item>
<setting-menu-item label="头部高度">
<n-input-number
<setting-menu-item label="顶部菜单位置">
<n-select
class="w-120px"
size="small"
:value="theme.headerStyle.height"
:step="1"
@update:value="handleHeaderHeight"
/>
</setting-menu-item>
<setting-menu-item label="多页签高度">
<n-input-number
class="w-120px"
size="small"
:value="theme.multiTabStyle.height"
:step="1"
@update:value="handleMultiTabHeight"
:value="theme.menuStyle.horizontalPosition"
:options="theme.menuStyle.horizontalPositionList"
@update:value="handleHorizontalMenuPosition"
/>
</setting-menu-item>
<setting-menu-item label="菜单展开宽度">
@ -45,18 +33,40 @@
@update:value="handleMixMenuWidth"
/>
</setting-menu-item>
<setting-menu-item label="固定头部和多页签">
<n-switch :value="splitMenu" :disabled="disabledSplitMenu" @update:value="handleFixedHeaderAndTab" />
</setting-menu-item>
<setting-menu-item label="头部高度">
<n-input-number
class="w-120px"
size="small"
:value="theme.headerStyle.height"
:step="1"
@update:value="handleHeaderHeight"
/>
</setting-menu-item>
<setting-menu-item label="多页签高度">
<n-input-number
class="w-120px"
size="small"
:value="theme.multiTabStyle.height"
:step="1"
@update:value="handleMultiTabHeight"
/>
</setting-menu-item>
</n-space>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import { NDivider, NSpace, NSwitch, NInputNumber } from 'naive-ui';
import { NDivider, NSpace, NSwitch, NSelect, NInputNumber } from 'naive-ui';
import { useThemeStore } from '@/store';
import { SettingMenuItem } from '../common';
const theme = useThemeStore();
const {
handleSplitMenu,
handleHorizontalMenuPosition,
handleFixedHeaderAndTab,
handleHeaderHeight,
handleMultiTabHeight,

View File

@ -1,7 +1,7 @@
<template>
<n-layout class="h-full" has-sider>
<global-sider v-if="theme.isVerticalNav" :z-index="3" />
<global-header v-if="isHorizontalMix" :z-index="2" />
<global-header v-if="isHorizontalMix" :z-index="4" />
<div class="flex-1-hidden flex h-full">
<global-sider v-if="isHorizontalMix" class="sider-margin" :z-index="3" />
<n-scrollbar
@ -39,6 +39,11 @@ const { scrollbar, resetScrollBehavior } = useScrollBehavior();
const routeProps = useRouteProps();
const isHorizontalMix = computed(() => theme.navStyle.mode === 'horizontal-mix');
const headerHeight = computed(() => {
const { height } = theme.headerStyle;
return `${height}px`;
});
const headerAndMultiTabHeight = computed(() => {
const {
headerStyle: { height: hHeight },
@ -59,7 +64,7 @@ watch(
z-index: 11;
}
.sider-margin {
margin-top: v-bind(headerAndMultiTabHeight);
margin-top: v-bind(headerHeight);
}
.content-padding {
padding-top: v-bind(headerAndMultiTabHeight);

View File

@ -1,5 +1,5 @@
import type { ThemeSettings } from '../interface';
import { EnumAnimate, EnumMultiTabMode } from '../enum';
import { EnumAnimate, EnumMultiTabMode, EnumHorizontalMenuPosition } from '../enum';
const themeColorList = [
'#409EFF',
@ -41,7 +41,13 @@ const themeSettings: ThemeSettings = {
mixWidth: 80,
collapsedWidth: 64,
fixed: true,
splitMenu: false
splitMenu: false,
horizontalPosition: 'flex-start',
horizontalPositionList: [
{ value: 'flex-start', label: EnumHorizontalMenuPosition['flex-start'] },
{ value: 'center', label: EnumHorizontalMenuPosition.center },
{ value: 'flex-end', label: EnumHorizontalMenuPosition['flex-end'] }
]
},
headerStyle: {
height: 56,

View File

@ -2,7 +2,7 @@ import { defineStore } from 'pinia';
import type { GlobalThemeOverrides } from 'naive-ui';
import { themeSettings } from '@/settings';
import { store } from '@/store';
import type { ThemeSettings, NavMode, MultiTabMode, AnimateType } from '@/interface';
import type { ThemeSettings, NavMode, MultiTabMode, AnimateType, HorizontalMenuPosition } from '@/interface';
import { getHoverAndPressedColor } from './helpers';
type ThemeState = ThemeSettings;
@ -85,6 +85,10 @@ const themeStore = defineStore({
this.menuStyle.mixWidth = width;
}
},
/** 更改顶部水平菜单的位置 */
handleHorizontalMenuPosition(position: HorizontalMenuPosition) {
this.menuStyle.horizontalPosition = position;
},
/** 更改头部的高度 */
handleHeaderHeight(height: number | null) {
if (height !== null) {