Files
certd/packages/ui/certd-client/src/vben/menu-ui/components/menu-item.vue
T
2025-06-29 14:09:09 +08:00

94 lines
2.9 KiB
Vue

<script lang="ts" setup>
import type { MenuItemProps, MenuItemRegistered } from "../types";
import { computed, onBeforeUnmount, onMounted, reactive, useSlots } from "vue";
import { useNamespace } from "../../composables";
import { VbenIcon, VbenTooltip } from "../../shadcn-ui";
import { MenuBadge } from "../components";
import { useMenu, useMenuContext, useSubMenuContext } from "../hooks";
interface Props extends MenuItemProps {}
defineOptions({ name: "MenuItem" });
const props = withDefaults(defineProps<Props>(), {
disabled: false,
});
const emit = defineEmits<{ click: [MenuItemRegistered] }>();
const slots = useSlots();
const { b, e, is } = useNamespace("menu-item");
const nsMenu = useNamespace("menu");
const rootMenu = useMenuContext();
const subMenu = useSubMenuContext();
const { parentMenu, parentPaths } = useMenu();
const active = computed(() => props.path === rootMenu?.activePath);
const menuIcon = computed(() => (active.value ? props.activeIcon || props.icon : props.icon));
const isTopLevelMenuItem = computed(() => parentMenu.value?.type.name === "Menu");
const collapseShowTitle = computed(() => rootMenu.props?.collapseShowTitle && isTopLevelMenuItem.value && rootMenu.props.collapse);
const showTooltip = computed(() => rootMenu.props.mode === "vertical" && isTopLevelMenuItem.value && rootMenu.props?.collapse && slots.title);
const item: MenuItemRegistered = reactive({
active,
parentPaths: parentPaths.value,
path: props.path || "",
});
/**
* 菜单项点击事件
*/
function handleClick() {
if (props.disabled) {
return;
}
if (props.click) {
props.click();
return;
}
rootMenu?.handleMenuItemClick?.({
parentPaths: parentPaths.value,
path: props.path,
});
emit("click", item);
}
onMounted(() => {
subMenu?.addSubMenu?.(item);
rootMenu?.addMenuItem?.(item);
});
onBeforeUnmount(() => {
subMenu?.removeSubMenu?.(item);
rootMenu?.removeMenuItem?.(item);
});
</script>
<template>
<li :class="[rootMenu.theme, b(), is('active', active), is('disabled', disabled), is('collapse-show-title', collapseShowTitle)]" role="menuitem" @click.stop="handleClick">
<VbenTooltip v-if="showTooltip" :content-class="[rootMenu.theme]" side="right">
<template #trigger>
<div :class="[nsMenu.be('tooltip', 'trigger')]">
<VbenIcon :class="nsMenu.e('icon')" :icon="menuIcon" fallback />
<slot></slot>
<span v-if="collapseShowTitle" :class="nsMenu.e('name')">
<slot name="title"></slot>
</span>
</div>
</template>
<slot name="title"></slot>
</VbenTooltip>
<div v-show="!showTooltip" :class="[e('content')]">
<MenuBadge v-if="rootMenu.props.mode !== 'horizontal'" class="right-2" v-bind="props" />
<VbenIcon :class="nsMenu.e('icon')" :icon="menuIcon" />
<slot></slot>
<slot name="title"></slot>
</div>
</li>
</template>