feat(menu): 改造菜单组件支持两级结构

- art-horizontal-menu: 顶部菜单只显示 isTopMenu: true 的一级菜单
- art-mixed-menu: 混合菜单顶部只显示 isTopMenu: true 的一级菜单
- 优化一级菜单激活状态判断,根据路由路径匹配一级菜单

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-06-12 19:51:21 +08:00
1 parent 3096b2c0dd
commit eab59bfdbf
2 files changed
+35 -42

No files matched your search

@@ -45,49 +45,33 @@
list: () => []
})
/**
* 当前活跃的一级菜单路径
* 根据当前路由路径判断所属的一级菜单
*/
const activeTopMenuPath = computed(() => {
const currentPath = String(route.meta.activePath || route.path)
return '/' + currentPath.split('/')[1]
})
/**
* 过滤后的菜单项列表
* 只显示未隐藏的菜单项
* 只显示一级菜单(isTopMenu: true)
*/
const filteredMenuItems = computed(() => {
return filterMenuItems(props.list)
return props.list.filter((item) => {
if (item.meta.isHide) {
return false
}
return item.meta.isTopMenu
})
})
/**
* 当前激活的路由路径
* 用于菜单高亮显示
*/
const routerPath = computed(() => String(route.meta.activePath || route.path))
/**
* 递归过滤菜单项,移除隐藏的菜单
* 如果一个父菜单的所有子菜单都被隐藏,则父菜单也会被隐藏
* @param items 菜单项数组
* @returns 过滤后的菜单项数组
*/
const filterMenuItems = (items: AppRouteRecord[]): AppRouteRecord[] => {
return items
.filter((item) => {
// 如果当前项被隐藏,直接过滤掉
if (item.meta.isHide) {
return false
}
// 如果有子菜单,递归过滤子菜单
if (item.children && item.children.length > 0) {
const filteredChildren = filterMenuItems(item.children)
// 如果所有子菜单都被过滤掉了,则隐藏父菜单
return filteredChildren.length > 0
}
// 叶子节点且未被隐藏,保留
return true
})
.map((item) => ({
...item,
children: item.children ? filterMenuItems(item.children) : undefined
}))
}
const routerPath = computed(() => activeTopMenuPath.value)
</script>
<style scoped>
@@ -106,13 +106,21 @@
/**
* 判断菜单项是否为激活状态
* 递归检查子菜单中是否包含当前路径
* 对于一级菜单:检查当前路径是否属于该菜单的子路径
* @param item 菜单项数据
* @returns 是否为激活状态
*/
const isMenuItemActive = (item: AppRouteRecord): boolean => {
const activePath = currentActivePath.value
// 获取一级菜单的基础路径
const topMenuPath = item.path || '/' + item.meta.title
// 检查当前路径是否以一级菜单路径开头
if (activePath.startsWith(topMenuPath) || activePath === topMenuPath) {
return true
}
// 如果有子菜单,递归检查子菜单
if (item.children?.length) {
return item.children.some((child) => {
@@ -123,20 +131,21 @@
})
}
// 直接比较路径
return item.path === activePath
return false
}
/**
* 预处理菜单列表
* 缓存每个菜单项的激活状态和格式化标题
* 只显示一级菜单(isTopMenu: true),并缓存激活状态和格式化标题
*/
const processedMenuList = computed<ProcessedMenuItem[]>(() => {
return props.list.map((item) => ({
...item,
isActive: isMenuItemActive(item),
formattedTitle: formatMenuTitle(item.meta.title)
}))
return props.list
.filter((item) => !item.meta.isHide && item.meta.isTopMenu)
.map((item) => ({
...item,
isActive: isMenuItemActive(item),
formattedTitle: formatMenuTitle(item.meta.title)
}))
})
/**