feat(menu): 改造菜单组件支持两级结构
- art-horizontal-menu: 顶部菜单只显示 isTopMenu: true 的一级菜单 - art-mixed-menu: 混合菜单顶部只显示 isTopMenu: true 的一级菜单 - 优化一级菜单激活状态判断,根据路由路径匹配一级菜单 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
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)
|
||||
}))
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user