当前位置: 首页 > news >正文

Element Plus Menu组件,实现点击目录而不是叶子节点也可以跳转,且支持高亮状态更新

<template> <div class="m-nav-wrap"> <div class="m-nav"> <div class="m-logo"></div> <!-- 移动端:汉堡菜单按钮 --> <div v-if="isMobile" class="m-hamburger" @click="drawerVisible = true"> <span></span> <span></span> <span></span> </div> <!-- 桌面端:横向菜单 --> <el-menu v-if="!isMobile" :default-active="activeIndex" class="m-nav-menu" mode="horizontal" background-color="#001A33" text-color="#fff" active-text-color="#3489EB" @select="handleSelect" > <template v-for="menu in menuConfig" :key="menu.index"> <!-- 特殊按钮样式(联系我们) --> <div v-if="menu.isSpecialButton" class="m-special-button-wrapper"> <div class="m-contact-button" :class="{ 'is-active': activeIndex === menu.index }" @click="handleSelect(menu.index, [menu.index])" > {{ menu.label }} </div> </div> <!-- 一级菜单(无子菜单) --> <el-menu-item v-else-if="!menu.children" :index="menu.index"> {{ menu.label }} </el-menu-item> <!-- 一级菜单(有子菜单) --> <el-sub-menu v-else :index="menu.index" @click.native="handleSelectMenu(menu.index)"> <template #title>{{ menu.label }}</template> <!-- 二级菜单 --> <template v-for="child in menu.children" :key="child.index"> <!-- 二级菜单项(无子菜单) --> <el-menu-item v-if="!child.children" :index="child.index"> {{ child.label }} </el-menu-item> <!-- 二级菜单(有子菜单) --> <el-sub-menu v-else :index="child.index"> <template #title>{{ child.label }}</template> <el-menu-item v-for="grandChild in child.children" :key="grandChild.index" :index="grandChild.index" > {{ grandChild.label }} </el-menu-item> </el-sub-menu> </template> </el-sub-menu> </template> </el-menu> </div> <!-- 移动端:侧边抽屉菜单 --> <el-drawer v-model="drawerVisible" direction="ltr" :size="280" class="m-mobile-drawer" > <el-menu :default-active="activeIndex" class="m-mobile-menu" mode="vertical" background-color="#001A33" text-color="#fff" active-text-color="#3489EB" :router="true" @select="handleMobileSelect" > <template v-for="menu in menuConfig" :key="menu.index"> <!-- 一级菜单(无子菜单) --> <el-menu-item v-if="!menu.children" :index="menu.index"> {{ menu.label }} </el-menu-item> <!-- 一级菜单(有子菜单) --> <el-sub-menu v-else :index="menu.index" @click.native="handleSelectMenu(menu.index)"> <template #title>{{ menu.label }}</template> <!-- 二级菜单 --> <template v-for="child in menu.children" :key="child.index"> <!-- 二级菜单项(无子菜单) --> <el-menu-item v-if="!child.children" :index="child.index"> {{ child.label }} </el-menu-item> <!-- 二级菜单(有子菜单) --> <el-sub-menu v-else :index="child.index"> <template #title>{{ child.label }}</template> <el-menu-item v-for="grandChild in child.children" :key="grandChild.index" :index="grandChild.index" > {{ grandChild.label }} </el-menu-item> </el-sub-menu> </template> </el-sub-menu> </template> </el-menu> </el-drawer> </div> </template> <script lang="ts" setup> import { ref, onMounted, watch } from 'vue' import { useRouter, useRoute } from 'vue-router' import { menuConfig, setDocumentTitle } from './menu-config' import { useResponsive } from './use-responsive' const router = useRouter() const route = useRoute() const activeIndex = ref('/') const drawerVisible = ref(false) // 响应式检测 const { isMobile } = useResponsive() // 桌面端菜单选择 const handleSelect = (key: string, keyPath: string[]) => { console.log('Selected:', key, keyPath) // 更新激活状态 activeIndex.value = key // 设置页面标题 setDocumentTitle(key) // 路由跳转(仅当 index 是有效路径时) if (key.startsWith('/')) { router.push({ path: key }) } } // 移动端菜单选择 const handleMobileSelect = (key: string, keyPath: string[]) => { handleSelect(key, keyPath) // 关闭抽屉 drawerVisible.value = false } const handleSelectMenu = (path: any) => { console.log('path', path) // 更新激活状态 activeIndex.value = path // 设置页面标题 setDocumentTitle(path) // 路由跳转 router.push({ path }) } // 监听路由变化,同步更新激活状态 watch( () => route.path, (newPath) => { activeIndex.value = newPath setDocumentTitle(newPath) } ) onMounted(() => { // 初始化当前路由 const currentPath = router.currentRoute.value.path activeIndex.value = currentPath // 设置初始页面标题 setDocumentTitle(currentPath) }) </script> <style lang="css" scoped src="./index.css"></style>
// 菜单配置 export interface MenuItem { index: string label: string title?: string // 用于设置 document.title children?: MenuItem[] isSpecialButton?: boolean // 是否为特殊按钮样式 } export const menuConfig: MenuItem[] = [ { index: '/', label: '首页', }, { index: '/productCenter/index', label: '产品中心', children: [ { index: '/productCenter/index', label: '快速入口', }, { index: '/productCenter/aiAppOpPlat', label: 'AI应用运营平台', }, ], }, { index: '/successStories/index', label: '成功故事', title: '成功故事', children: [ { index: '/successStories/index', label: '快速入口', }, { index: '/successStories/edu', label: '教育', }, ], }, { index: '/partner', label: '合作伙伴', title: '合作伙伴', }, { index: '4', label: '关于我们', title: '关于我们', children: [ { index: '/about', label: '公司介绍', title: '公司介绍', }, ], }, { index: '6', label: '资讯中心', title: '资讯中心', children: [ { index: '/news', label: '最新资讯', title: '最新资讯', }, ], }, { index: '/contact', label: '联系我们', title: '联系我们', isSpecialButton: true, }, ] // 网站名称后缀 export const SITE_NAME = '通圆数智' // 根据 index 查找菜单标题 export function findMenuTitle( menuIndex: string, menus: MenuItem[] = menuConfig, ): string | null { for (const menu of menus) { if (menu.index === menuIndex) { return menu.title || menu.label } if (menu.children) { const title = findMenuTitle(menuIndex, menu.children) if (title) return title } } return null } // 设置页面标题 export function setDocumentTitle(menuIndex: string) { const title = findMenuTitle(menuIndex) if (title) { document.title = `${title} - ${SITE_NAME}` } }
http://www.jsqmd.com/news/318188/

相关文章:

  • 多大模型 API 统一调用解决方案:6 个 GitHub 开源项目深度推荐
  • 2026年环保移动公厕厂家最新推荐:免水冲移动公厕/环保移动公厕/移动厕所/选择指南
  • 股票资金流实时数据接口分享
  • Kimi K2.5 模型上线 AtomGit,全能 Agent 模型,视觉理解、代码和思考 All in One
  • 2026年在线浓度计行业深度解析与厂家推荐:豆浆/酒精/尿素/切削液/乳化液/盐水在线浓度计头部厂家
  • JavaScript 中 Proxy 的 apply 捕获器(trap)的语法和具体用法
  • AtomGit 开源雷达 第 1 期:这些开源项目,正在被开发者偷偷使用
  • 电容漏电流的测量方式
  • 低空经济产业动态——2025 年度盘点与趋势观察
  • 2026年北京肝肿瘤诊疗机构top5推荐指南:北京甲状腺肿瘤/北京直肠肿瘤/北京红斑狼疮/北京结肠肿瘤/北京肾肿瘤/选择指南
  • 2026中国软件供应链安全产业全景图谱与核心厂商能力分析
  • 腾讯轻量云服务器的优点
  • 2026年高口碑卫生无纺布和包装无纺布生产厂家推荐,助你轻松选择优质产品!
  • 电子签章选型指南:云巨头生态服务与垂直专业厂商的六大维度解析
  • 跨境直播必看:深度对比Whatnot与Tiktok两个直播电商平台的核心差异
  • 什么情况下使用腾讯云服务器
  • 2026国内最新衣柜专用板材十大公司推荐!山东等地优质板材品牌权威榜单发布,环保品质双优助力高品质家居生活
  • 锂电池建模仿真:等效电路模型
  • 最长的白色段
  • 【vtkPolyDataPointSampler 】——多边形数据点采样技术详解
  • 四川市场调查优质机构推荐榜:成都找人公司电话/成都找人电话/找人电话/四川市场调查公司电话/四川市场调查电话/四川找人公司/选择指南
  • 2026年高铁广告公司哪家好:五大专业优质高铁广告公司权威盘点
  • Tailwind CSS
  • 【Global ID概念】——vtkGenerateGlobalIds应用详解
  • 2026年植发厉害/靠谱/专业/技术好/评价高/副作用少的医生推荐口碑榜 加密种植/术后无痕/快速恢复
  • 国资委46号令落地:穿透式监管如何重塑央企合同治理逻辑
  • AI率从85%降到10%!DeepSeek四大降AI指令+3款保命神器实测(2026最新)
  • 实验室气体管路安装改造服务公司哪家好?推荐行业内知名的服务商
  • QLoRA技术详解,单GPU微调650亿参数模型,性能媲美ChatGPT
  • 适配刘海