add 一级菜单样式修改

This commit is contained in:
Asoka 2025-06-05 13:32:23 +08:00
parent b55ef58246
commit 012811712b
3 changed files with 215 additions and 40 deletions

View File

@ -3,9 +3,8 @@
<div class="left-section"> <div class="left-section">
<Logo v-if="setIsShowLogo" /> <Logo v-if="setIsShowLogo" />
</div> </div>
<Horizontal :menuList="state.menuList" />
<div class="right-section"> <div class="right-section">
<Horizontal :menuList="state.menuList" />
<User /> <User />
</div> </div>
</div> </div>
@ -81,11 +80,8 @@ const filterRoutesFun = <T extends RouteItem>(arr: T[]): T[] => {
.filter((item: T) => !item.meta?.isHide) .filter((item: T) => !item.meta?.isHide)
.map((item: T) => { .map((item: T) => {
item = Object.assign({}, item) item = Object.assign({}, item)
// children //
// if (item.children) item.children = filterRoutesFun(item.children) if (item.children) item.children = filterRoutesFun(item.children)
if (item.children) {
delete (item as any).children //
}
return item return item
}) })
} }

View File

@ -1,25 +1,34 @@
<template> <template>
<div class="el-menu-horizontal-warp"> <div class="el-menu-horizontal-warp">
<el-menu router :default-active="state.defaultActive" background-color="transparent" mode="horizontal"> <!-- 将四个模块合并为一个下拉菜单类似语言切换 -->
<template v-for="val in menuLists"> <el-dropdown
<el-sub-menu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path"> :show-timeout="70"
<template #title> :hide-timeout="50"
<SvgIcon :name="val.meta.icon" /> trigger="click"
<span>{{ $t(val.meta.title) + '111111'}}</span> @command="onModuleCommand"
class="module-dropdown"
>
<div class="module-selector">
<SvgIcon :name="currentModule.icon" />
<span class="module-title">{{ currentModule.title }}</span>
<el-icon class="el-icon--right">
<ele-ArrowDown />
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-for="module in moduleList"
:key="module.path"
:command="module.path"
:class="{ 'is-active': isCurrentModule(module.path) }"
>
<SvgIcon :name="module.icon" class="dropdown-icon" />
{{ module.title }}
</el-dropdown-item>
</el-dropdown-menu>
</template> </template>
<SubItem :chil="val.children" /> </el-dropdown>
</el-sub-menu>
<template v-else>
<el-menu-item :index="val.path" :key="val.path">
<template #title v-if="!val.meta.isLink || (val.meta.isLink && val.meta.isIframe)">
<SvgIcon :name="val.meta.icon" />
{{ $t(val.meta.title) + '222222' }}
</template>
</el-menu-item>
</template>
</template>
</el-menu>
</div> </div>
</template> </template>
@ -27,6 +36,7 @@
import { defineAsyncComponent, reactive, computed, onBeforeMount } from 'vue' import { defineAsyncComponent, reactive, computed, onBeforeMount } from 'vue'
import { useRoute, onBeforeRouteUpdate, RouteRecordRaw, useRouter } from 'vue-router' import { useRoute, onBeforeRouteUpdate, RouteRecordRaw, useRouter } from 'vue-router'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useI18n } from 'vue-i18n'
import { useRoutesList } from '/@/stores/routesList' import { useRoutesList } from '/@/stores/routesList'
import { useThemeConfig } from '/@/stores/themeConfig' import { useThemeConfig } from '/@/stores/themeConfig'
import other from '/@/utils/other' import other from '/@/utils/other'
@ -35,9 +45,10 @@ import { treeToList, listToTree, filterList } from '/@/utils/tree'
import { cloneDeep } from 'lodash-es' import { cloneDeep } from 'lodash-es'
const router = useRouter() const router = useRouter()
const { t } = useI18n()
// //
// const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue')) // // const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue')) // 使el-dropdown
// //
const props = defineProps({ const props = defineProps({
@ -56,12 +67,35 @@ const { themeConfig } = storeToRefs(storesThemeConfig)
const route = useRoute() const route = useRoute()
const state = reactive({ const state = reactive({
defaultActive: '' as string | undefined, defaultActive: '' as string | undefined,
currentModulePath: '' as string,
}) })
// //
const menuLists = computed(() => { const menuLists = computed(() => {
return <RouteItems>props.menuList return <RouteItems>props.menuList
}) })
// -
const moduleList = computed(() => {
return menuLists.value.map(item => ({
path: item.path,
title: item.meta?.title ? t(item.meta.title) : '未命名模块',
icon: item.meta?.icon || 'ele-Menu'
}))
})
//
const currentModule = computed(() => {
const current = moduleList.value.find(module =>
state.currentModulePath === module.path ||
route.path.startsWith(module.path)
)
return current || moduleList.value[0] || {
path: '',
title: '选择模块',
icon: 'ele-Menu'
}
})
// //
const filterRoutesFun = <T extends RouteItem>(arr: T[]): T[] => { const filterRoutesFun = <T extends RouteItem>(arr: T[]): T[] => {
return arr return arr
@ -124,14 +158,80 @@ const setCurrentRouterHighlight = (currentRoute: RouteToFrom) => {
const onALinkClick = (val: RouteItem) => { const onALinkClick = (val: RouteItem) => {
other.handleOpenLink(val) other.handleOpenLink(val)
} }
//
const onModuleCommand = (path: string) => {
//
state.currentModulePath = path
//
const selectedModule = menuLists.value.find(item => item.path === path)
if (!selectedModule) return
// 使
if (selectedModule.meta?.isLink && !selectedModule.meta?.isIframe) {
onALinkClick(selectedModule)
return
}
//
if (selectedModule.children && selectedModule.children.length > 0) {
const firstChild = selectedModule.children.find((child: RouteItem) => !child.meta?.isHide)
if (firstChild) {
router.push(firstChild.path)
} else {
router.push(selectedModule.path)
}
} else {
//
router.push(selectedModule.path)
}
//
mittBus.emit('getBreadcrumbIndexSetFilterRoutes')
if (themeConfig.value.layout === 'classic' && themeConfig.value.isClassicSplitMenu) {
mittBus.emit('setSendClassicChildren', setSendClassicChildren(path))
}
}
//
const isCurrentModule = (path: string): boolean => {
return state.currentModulePath === path || route.path.startsWith(path)
}
// //
onBeforeMount(() => { onBeforeMount(() => {
setCurrentRouterHighlight(route) setCurrentRouterHighlight(route)
//
initCurrentModule()
}) })
//
const initCurrentModule = () => {
//
const currentPath = route.path
const matchedModule = menuLists.value.find(module =>
currentPath.startsWith(module.path) && module.path !== '/'
)
if (matchedModule) {
state.currentModulePath = matchedModule.path
} else if (menuLists.value.length > 0) {
//
state.currentModulePath = menuLists.value[0].path
}
}
// //
onBeforeRouteUpdate((to) => { onBeforeRouteUpdate((to) => {
// https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G // https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
setCurrentRouterHighlight(to) setCurrentRouterHighlight(to)
//
const matchedModule = menuLists.value.find(module =>
to.path.startsWith(module.path) && module.path !== '/'
)
if (matchedModule) {
state.currentModulePath = matchedModule.path
}
// tagsView // tagsView
let { layout, isClassicSplitMenu } = themeConfig.value let { layout, isClassicSplitMenu } = themeConfig.value
if (layout === 'classic' && isClassicSplitMenu) { if (layout === 'classic' && isClassicSplitMenu) {
@ -145,17 +245,100 @@ onBeforeRouteUpdate((to) => {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
margin-right: 30px; margin-right: 30px;
display: flex;
align-items: center;
height: 100%;
.module-dropdown {
.module-selector {
height: 50px;
line-height: 50px;
padding: 0 10px;
cursor: pointer;
display: flex;
align-items: center;
gap: 5px;
color: var(--next-bg-topBarColor);
background: transparent;
border: none;
border-radius: 6px;
font-size: 14px;
transition: all 0.3s;
white-space: nowrap;
.module-title {
font-weight: 500;
}
&:hover {
background: var(--next-color-user-hover);
color: var(--next-bg-topBarColor);
}
}
}
//
:deep(.el-dropdown-menu) {
border-radius: 8px;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
border: 1px solid var(--el-border-color-light);
min-width: 180px;
.el-dropdown-menu__item {
display: flex;
align-items: center;
padding: 12px 16px;
transition: all 0.3s;
border-radius: 6px;
margin: 4px 6px;
.dropdown-icon {
margin-right: 10px;
font-size: 16px;
width: 16px;
height: 16px;
}
&:hover {
background: var(--next-color-user-hover);
color: var(--next-bg-topBarColor);
}
&.is-active {
background: var(--next-color-user-hover);
color: var(--next-bg-topBarColor);
font-weight: 600;
.dropdown-icon {
color: var(--next-bg-topBarColor);
}
}
}
}
//
:deep(.el-scrollbar__bar.is-vertical) { :deep(.el-scrollbar__bar.is-vertical) {
display: none; display: none;
} }
:deep(a) { :deep(a) {
width: 100%; width: 100%;
} }
.el-menu.el-menu--horizontal {
display: flex; //
height: 100%; @media (max-width: 768px) {
width: 100%; .module-dropdown {
box-sizing: border-box; .module-selector {
padding: 0 12px;
height: 40px;
line-height: 40px;
font-size: 14px;
.module-title {
margin-left: 6px;
margin-right: 6px;
}
}
}
} }
} }
</style> </style>

View File

@ -385,17 +385,13 @@
padding: 0px; padding: 0px;
} }
/* 隐藏水平菜单的下拉效果 */ /* 水平菜单下拉样式优化 */
.el-menu--horizontal { .el-menu--horizontal {
.el-sub-menu .el-sub-menu__icon-arrow { .el-sub-menu .el-sub-menu__icon-arrow {
display: none !important; /* 隐藏下拉箭头 */ transition: transform 0.3s;
} }
.el-sub-menu__title:hover + .el-menu { .el-sub-menu.is-opened .el-sub-menu__icon-arrow {
display: none !important; /* 隐藏下拉菜单 */ transform: rotate(180deg);
}
.el-popper.is-pure.is-light {
display: none !important; /* 完全隐藏下拉弹出层 */
} }
} }