From b0530ed9211230227a8f94e394eda779d5ae5fc1 Mon Sep 17 00:00:00 2001 From: birt <2499248221@qq.com> Date: 星期日, 13 四月 2025 01:51:52 +0800 Subject: [PATCH] birtzhang --- zhitan-vue/src/components/TopNav/index.vue | 326 ++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 243 insertions(+), 83 deletions(-) diff --git a/zhitan-vue/src/components/TopNav/index.vue b/zhitan-vue/src/components/TopNav/index.vue index 52b40ea..7c42971 100644 --- a/zhitan-vue/src/components/TopNav/index.vue +++ b/zhitan-vue/src/components/TopNav/index.vue @@ -1,35 +1,30 @@ <template> - <el-menu - :default-active="activeMenu" - mode="horizontal" - @select="handleSelect" - :ellipsis="false" - > - <template v-for="(item, index) in topMenus"> - <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"> - <svg-icon - v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" - :icon-class="item.meta.icon"/> - {{ item.meta.title }} - </el-menu-item> - </template> - - <!-- 椤堕儴鑿滃崟瓒呭嚭鏁伴噺鎶樺彔 --> - <el-sub-menu :style="{'--theme': theme}" index="more" v-if="topMenus.length > visibleNumber"> - <template #title>鏇村鑿滃崟</template> - <template v-for="(item, index) in topMenus"> - <el-menu-item - :index="item.path" - :key="index" - v-if="index >= visibleNumber"> - <svg-icon - v-if="item.meta && item.meta.icon && item.meta.icon !== '#'" - :icon-class="item.meta.icon"/> - {{ item.meta.title }} - </el-menu-item> - </template> - </el-sub-menu> - </el-menu> + <div class="top-nav-container"> + <div class="scroll-arrow left-arrow" @click="scrollLeft" v-show="canScrollLeft"> + <el-icon><arrow-left /></el-icon> + </div> + + <div class="menu-container" ref="menuContainer"> + <el-menu + :default-active="activeMenu" + mode="horizontal" + @select="handleSelect" + :ellipsis="false" + class="top-menu" + :class="{ 'theme-dark': theme === 'dark' }" + > + <template v-for="(item, index) in topMenus" :key="index"> + <el-menu-item :style="{'--theme': theme}" :index="item.path"> + {{ item.meta.title }} + </el-menu-item> + </template> + </el-menu> + </div> + + <div class="scroll-arrow right-arrow" @click="scrollRight" v-show="canScrollRight"> + <el-icon><arrow-right /></el-icon> + </div> + </div> </template> <script setup> @@ -38,9 +33,13 @@ import useAppStore from '@/store/modules/app' import useSettingsStore from '@/store/modules/settings' import usePermissionStore from '@/store/modules/permission' +import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue' -// 椤堕儴鏍忓垵濮嬫暟 -const visibleNumber = ref(null); +// 婊氬姩鐩稿叧 +const menuContainer = ref(null); +const canScrollLeft = ref(false); +const canScrollRight = ref(false); + // 褰撳墠婵�娲昏彍鍗曠殑 index const currentIndex = ref(null); // 闅愯棌渚ц竟鏍忚矾鐢� @@ -102,9 +101,13 @@ const tmpPath = path.substring(1, path.length); activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/")); if (!route.meta.link) { - appStore.toggleSideBarHide(false); + appStore.toggleSideBarHide(false); } - } else if(!route.children) { + } else if (path === '/index' || path === '/') { + // 棣栭〉鏃堕殣钘忎晶杈规爮 + activePath = path; + appStore.toggleSideBarHide(true); + } else if (!route.children) { activePath = path; appStore.toggleSideBarHide(true); } @@ -112,36 +115,76 @@ return activePath; }) -function setVisibleNumber() { - const width = document.body.getBoundingClientRect().width / 3; - visibleNumber.value = parseInt(width / 85); +function updateScrollButtons() { + if (!menuContainer.value) return; + + const container = menuContainer.value; + canScrollLeft.value = container.scrollLeft > 10; + canScrollRight.value = container.scrollLeft < (container.scrollWidth - container.clientWidth - 10); +} + +function scrollLeft() { + if (!menuContainer.value) return; + menuContainer.value.scrollBy({ left: -200, behavior: 'smooth' }); + setTimeout(updateScrollButtons, 300); +} + +function scrollRight() { + if (!menuContainer.value) return; + menuContainer.value.scrollBy({ left: 200, behavior: 'smooth' }); + setTimeout(updateScrollButtons, 300); } function handleSelect(key, keyPath) { currentIndex.value = key; const route = routers.value.find(item => item.path === key); + if (isHttp(key)) { // http(s):// 璺緞鏂扮獥鍙f墦寮� window.open(key, "_blank"); - } else if (!route || !route.children) { - // 娌℃湁瀛愯矾鐢辫矾寰勫唴閮ㄦ墦寮� + return; + } + + if (key === '/index' || key === '/') { + // 棣栭〉鏃舵樉绀烘姌鍙犵殑渚ц竟鏍忥紝鑰屼笉鏄殣钘� + router.push({ path: key }); + appStore.showCollapsedSidebar(); + return; + } + + // 妫�鏌ユ槸鍚︽湁瀛愯矾鐢� + if (route && route.children && route.children.length > 0) { + // 鏈夊瓙璺敱锛屾樉绀轰晶杈规爮 + activeRoutes(key); + const firstChild = route.children[0]; + const path = firstChild.path.startsWith('/') ? firstChild.path : `${key}/${firstChild.path}`; + if (firstChild.query) { + router.push({ path, query: firstChild.query }); + } else { + router.push({ path }); + } + } else { + // 娌℃湁瀛愯矾鐢憋紝闅愯棌渚ц竟鏍� const routeMenu = childrenMenus.value.find(item => item.path === key); if (routeMenu && routeMenu.query) { - let query = JSON.parse(routeMenu.query); - router.push({ path: key, query: query }); + // query 宸茬粡鍦� permission.js 涓澶勭悊涓哄璞★紝鏃犻渶鍐嶆瑙f瀽 + router.push({ path: key, query: routeMenu.query }); } else { router.push({ path: key }); } appStore.toggleSideBarHide(true); - } else { - // 鏄剧ず宸︿晶鑱斿姩鑿滃崟 - activeRoutes(key); - appStore.toggleSideBarHide(false); } } function activeRoutes(key) { let routes = []; + if (key === '/index' || key === '/') { + // 棣栭〉鏃舵樉绀烘姌鍙犵殑渚ц竟鏍忥紝鑰屼笉鏄殣钘� + appStore.showCollapsedSidebar(); + return []; + } + + // 鏌ユ壘鍖归厤鐨勮矾鐢� if (childrenMenus.value && childrenMenus.value.length > 0) { childrenMenus.value.map((item) => { if (key == item.parentPath || (key == "index" && "" == item.path)) { @@ -149,66 +192,183 @@ } }); } + if(routes.length > 0) { + // 鏈夊瓙璺敱锛屽垯鏄剧ず渚ц竟鏍� permissionStore.setSidebarRouters(routes); + appStore.toggleSideBarHide(false); } else { + // 娌℃湁瀛愯矾鐢憋紝闅愯棌渚ц竟鏍� appStore.toggleSideBarHide(true); } return routes; } onMounted(() => { - window.addEventListener('resize', setVisibleNumber) -}) -onBeforeUnmount(() => { - window.removeEventListener('resize', setVisibleNumber) + // 鏍规嵁褰撳墠璺敱鍐冲畾鏄惁鏄剧ず渚ц竟鏍忥紝鑰屼笉鏄洿鎺ラ殣钘� + const currentPath = route.path; + if (currentPath === '/index' || currentPath === '/') { + // 濡傛灉褰撳墠鏄椤碉紝鑷姩璺宠浆鍒扮涓�涓姩鎬佽矾鐢� + if (topMenus.value.length > 0) { + const firstRoute = topMenus.value[0]; + handleSelect(firstRoute.path); + } + } else { + // 妫�鏌ュ綋鍓嶈矾鐢辨槸鍚﹂渶瑕佹樉绀轰晶杈规爮 + const routeConfig = routers.value.find(item => currentPath.startsWith(item.path) && item.path !== '/'); + if (routeConfig && routeConfig.children && routeConfig.children.length > 0) { + // 鏈夊瓙鑿滃崟锛屾樉绀轰晶杈规爮 + activeRoutes(routeConfig.path); + appStore.toggleSideBarHide(false); + } else { + // 鏃犲瓙鑿滃崟锛屽彲浠ラ殣钘忎晶杈规爮 + appStore.toggleSideBarHide(true); + } + } + + // 鐩戝惉婊氬姩鐘舵�� + if (menuContainer.value) { + menuContainer.value.addEventListener('scroll', updateScrollButtons); + nextTick(() => { + updateScrollButtons(); + }); + } + + window.addEventListener('resize', () => { + updateScrollButtons(); + }); }) -onMounted(() => { - setVisibleNumber() +onBeforeUnmount(() => { + if (menuContainer.value) { + menuContainer.value.removeEventListener('scroll', updateScrollButtons); + } + window.removeEventListener('resize', updateScrollButtons); }) </script> <style lang="scss"> -.topmenu-container.el-menu--horizontal > .el-menu-item { - float: left; - height: 50px !important; - line-height: 50px !important; - color: #999093 !important; - padding: 0 5px !important; - margin: 0 10px !important; +.top-nav-container { + display: flex; + align-items: center; + flex: 1; + position: relative; + height: 60px; + overflow: hidden; + padding: 0 40px; /* Increase padding for arrows */ + + .scroll-arrow { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + background: rgba(255, 255, 255, 0.2); + border-radius: 50%; + cursor: pointer; + color: #ffffff; + z-index: 20; + opacity: 0; + transition: opacity 0.3s; + position: absolute; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); + + &:hover { + background: rgba(255, 255, 255, 0.3); + } + + &.left-arrow { + left: 8px; + } + + &.right-arrow { + right: 8px; + } + } + + &:hover { + .scroll-arrow { + opacity: 1; + } + } + + .menu-container { + width: 100%; + height: 100%; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ + + &::-webkit-scrollbar { + display: none; /* Chrome, Safari, Opera */ + } + } } -.topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-sub-menu.is-active .el-submenu__title { - border-bottom: 2px solid #{'var(--theme)'} !important; - color: #303133; +.top-menu { + height: 60px; + border-bottom: none !important; + white-space: nowrap; + background: transparent !important; + + &.theme-dark { + background: #002866 !important; + } } -/* sub-menu item */ -.topmenu-container.el-menu--horizontal > .el-sub-menu .el-sub-menu__title { - float: left; - height: 50px !important; - line-height: 50px !important; - color: #999093 !important; - padding: 0 5px !important; - margin: 0 10px !important; -} - -/* 鑳屾櫙鑹查殣钘� */ -.topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover { - background-color: #ffffff !important; +.el-menu--horizontal { + border-bottom: none !important; + + > .el-menu-item { + display: inline-block; + float: none; + height: 60px !important; + line-height: 60px !important; + color: #ffffff !important; + padding: 0 20px !important; + margin: 0 !important; + border-bottom: none !important; + position: relative; + font-size: 16px; + + &.is-active { + background-color: transparent !important; + color: #ffffff !important; + font-weight: bold; + + &::after { + content: ''; + position: absolute; + bottom: 10px; + left: 50%; + transform: translateX(-50%); + width: calc(100% - 40px); + height: 2px; + background-color: #ffffff; + } + } + + &:hover { + background-color: rgba(255, 255, 255, 0.1) !important; + color: #ffffff !important; + } + } } /* 鍥炬爣鍙抽棿璺� */ -.topmenu-container .svg-icon { - margin-right: 4px; +.svg-icon { + margin-right: 8px; + color: #ffffff; } -/* topmenu more arrow */ -.topmenu-container .el-sub-menu .el-sub-menu__icon-arrow { - position: static; - vertical-align: middle; - margin-left: 8px; - margin-top: 0px; +/* 棣栭〉鎸夐挳鏍峰紡 */ +.el-menu-item:first-child { + margin-left: 0 !important; + font-weight: bold; + + .svg-icon { + font-size: 18px; + } } </style> -- Gitblit v1.9.3