menu-item.vue
2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<script lang="ts" setup>
import type { MenuItemProps, MenuItemRegistered } from '../types';
import { computed, onBeforeUnmount, onMounted, reactive, useSlots } from 'vue';
import { useNamespace } from '@vben-core/composables';
import { VbenIcon, VbenTooltip } from '@vben-core/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;
}
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>