mirror of
https://github.com/fantastic-admin/basic.git
synced 2026-10-07 13:28:38 +08:00
refactor: 最子级菜单项用 <a> 渲染
This commit is contained in:
@@ -19,8 +19,6 @@ const props = withDefaults(
|
||||
},
|
||||
)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const activeIndex = ref<MenuInjection['activeIndex']>(props.value)
|
||||
const items = ref<MenuInjection['items']>({})
|
||||
const subMenus = ref<MenuInjection['subMenus']>({})
|
||||
@@ -87,16 +85,11 @@ function setSubMenusActive(index: string) {
|
||||
})
|
||||
}
|
||||
|
||||
const handleMenuItemClick: MenuInjection['handleMenuItemClick'] = (index, meta) => {
|
||||
const handleMenuItemClick: MenuInjection['handleMenuItemClick'] = (index) => {
|
||||
if (props.mode === 'horizontal' || props.collapse) {
|
||||
openedMenus.value = []
|
||||
}
|
||||
setSubMenusActive(index)
|
||||
if (meta?.link) {
|
||||
window.open(meta.link)
|
||||
return
|
||||
}
|
||||
router.push(index)
|
||||
}
|
||||
const handleSubMenuClick: MenuInjection['handleSubMenuClick'] = (index, indexPath) => {
|
||||
if (openedMenus.value.includes(index)) {
|
||||
@@ -175,7 +168,7 @@ provide(rootMenuInjectionKey, reactive({
|
||||
>
|
||||
<template v-for="(item, index) in menu" :key="index">
|
||||
<SubMenu v-if="item.children?.length" :menu="item" :unique-key="[item.path ?? JSON.stringify(item)]" />
|
||||
<Item v-else :item="item" :unique-key="[item.path ?? JSON.stringify(item)]" @click="handleMenuItemClick(item.path ?? JSON.stringify(item), item.meta)" />
|
||||
<Item v-else :item="item" :unique-key="[item.path ?? JSON.stringify(item)]" @click="handleMenuItemClick(item.path ?? JSON.stringify(item))" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -43,37 +43,45 @@ defineExpose({
|
||||
active: isItemActive,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="group menu-item-container h-full w-full flex cursor-pointer items-center justify-between gap-1 px-5 py-4 text-[var(--g-sub-sidebar-menu-color)] transition-all hover:(bg-[var(--g-sub-sidebar-menu-hover-bg)] text-[var(--g-sub-sidebar-menu-hover-color)])" :class="{
|
||||
'text-[var(--g-sub-sidebar-menu-active-color)]! bg-[var(--g-sub-sidebar-menu-active-bg)]!': isItemActive,
|
||||
'px-3!': rootMenu.isMenuPopup && level === 0,
|
||||
}" :title="typeof item.meta?.title === 'function' ? item.meta?.title() : item.meta?.title"
|
||||
>
|
||||
<div
|
||||
class="inline-flex flex-1 items-center justify-center gap-[12px]" :class="{
|
||||
'flex-col': rootMenu.isMenuPopup && level === 0 && rootMenu.props.mode === 'vertical',
|
||||
'gap-1!': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName,
|
||||
'w-full': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName && rootMenu.props.mode === 'vertical',
|
||||
}" :style="indentStyle"
|
||||
<router-link v-slot="{ href }" custom :to="uniqueKey.at(-1) ?? ''">
|
||||
<component
|
||||
:is="subMenu ? 'div' : 'a'" v-bind="{
|
||||
...(!subMenu && {
|
||||
href: item.meta?.link ? item.meta.link : href,
|
||||
target: item.meta?.link ? '_blank' : '_self',
|
||||
class: 'no-underline',
|
||||
}),
|
||||
}" class="group menu-item-container h-full w-full flex cursor-pointer items-center justify-between gap-1 px-5 py-4 text-[var(--g-sub-sidebar-menu-color)] transition-all hover:(bg-[var(--g-sub-sidebar-menu-hover-bg)] text-[var(--g-sub-sidebar-menu-hover-color)])" :class="{
|
||||
'text-[var(--g-sub-sidebar-menu-active-color)]! bg-[var(--g-sub-sidebar-menu-active-bg)]!': isItemActive,
|
||||
'px-3!': rootMenu.isMenuPopup && level === 0,
|
||||
}" :title="typeof item.meta?.title === 'function' ? item.meta?.title() : item.meta?.title"
|
||||
>
|
||||
<SvgIcon v-if="props.item.meta?.icon" :name="props.item.meta.icon" :size="20" class="menu-item-container-icon transition-transform group-hover:scale-120" async />
|
||||
<span
|
||||
v-if="!(rootMenu.isMenuPopup && level === 0 && !rootMenu.props.showCollapseName)" class="w-0 flex-1 truncate text-sm transition-height transition-opacity transition-width"
|
||||
:class="{
|
||||
'opacity-0 w-0 h-0': rootMenu.isMenuPopup && level === 0 && !rootMenu.props.showCollapseName,
|
||||
'w-full text-center': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName,
|
||||
}"
|
||||
<div
|
||||
class="inline-flex flex-1 items-center justify-center gap-[12px]" :class="{
|
||||
'flex-col': rootMenu.isMenuPopup && level === 0 && rootMenu.props.mode === 'vertical',
|
||||
'gap-1!': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName,
|
||||
'w-full': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName && rootMenu.props.mode === 'vertical',
|
||||
}" :style="indentStyle"
|
||||
>
|
||||
{{ typeof item.meta?.title === 'function' ? item.meta?.title() : item.meta?.title }}
|
||||
</span>
|
||||
</div>
|
||||
<i
|
||||
v-if="subMenu && !(rootMenu.isMenuPopup && level === 0)" class="relative ml-1 w-[10px] after:(absolute h-[1.5px] w-[6px] bg-current transition-transform-200 content-empty -translate-y-[1px]) before:(absolute h-[1.5px] w-[6px] bg-current transition-transform-200 content-empty -translate-y-[1px])" :class="[
|
||||
expand ? 'before:(-rotate-45 -translate-x-[2px]) after:(rotate-45 translate-x-[2px])' : 'before:(rotate-45 -translate-x-[2px]) after:(-rotate-45 translate-x-[2px])',
|
||||
rootMenu.isMenuPopup && level === 0 && 'opacity-0',
|
||||
rootMenu.isMenuPopup && level !== 0 && '-rotate-90 -top-[1.5px]',
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
<SvgIcon v-if="props.item.meta?.icon" :name="props.item.meta.icon" :size="20" class="menu-item-container-icon transition-transform group-hover:scale-120" async />
|
||||
<span
|
||||
v-if="!(rootMenu.isMenuPopup && level === 0 && !rootMenu.props.showCollapseName)" class="w-0 flex-1 truncate text-sm transition-height transition-opacity transition-width"
|
||||
:class="{
|
||||
'opacity-0 w-0 h-0': rootMenu.isMenuPopup && level === 0 && !rootMenu.props.showCollapseName,
|
||||
'w-full text-center': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName,
|
||||
}"
|
||||
>
|
||||
{{ typeof item.meta?.title === 'function' ? item.meta?.title() : item.meta?.title }}
|
||||
</span>
|
||||
</div>
|
||||
<i
|
||||
v-if="subMenu && !(rootMenu.isMenuPopup && level === 0)" class="relative ml-1 w-[10px] after:(absolute h-[1.5px] w-[6px] bg-current transition-transform-200 content-empty -translate-y-[1px]) before:(absolute h-[1.5px] w-[6px] bg-current transition-transform-200 content-empty -translate-y-[1px])" :class="[
|
||||
expand ? 'before:(-rotate-45 -translate-x-[2px]) after:(rotate-45 translate-x-[2px])' : 'before:(rotate-45 -translate-x-[2px]) after:(-rotate-45 translate-x-[2px])',
|
||||
rootMenu.isMenuPopup && level === 0 && 'opacity-0',
|
||||
rootMenu.isMenuPopup && level !== 0 && '-rotate-90 -top-[1.5px]',
|
||||
]"
|
||||
/>
|
||||
</component>
|
||||
</router-link>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -114,7 +114,7 @@ function handleClick() {
|
||||
rootMenu.handleSubMenuClick(index, props.uniqueKey)
|
||||
}
|
||||
else {
|
||||
rootMenu.handleMenuItemClick(index, props.menu.meta)
|
||||
rootMenu.handleMenuItemClick(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface MenuInjection {
|
||||
isMenuPopup: boolean
|
||||
openMenu: (index: string, indexPath: string[]) => void
|
||||
closeMenu: (index: string | string[]) => void
|
||||
handleMenuItemClick: (index: string, meta?: Menu.recordRaw['meta']) => void
|
||||
handleMenuItemClick: (index: string) => void
|
||||
handleSubMenuClick: (index: string, indexPath: string[]) => void
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user