item.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <script setup lang="ts">
  2. import type { SubMenuItemProps } from './types'
  3. import { ref } from 'vue'
  4. import { rootMenuInjectionKey } from './types'
  5. defineOptions({
  6. name: 'SubMenuItem',
  7. })
  8. const props = withDefaults(
  9. defineProps<SubMenuItemProps>(),
  10. {
  11. level: 0,
  12. subMenu: false,
  13. expand: false,
  14. },
  15. )
  16. const rootMenu = inject(rootMenuInjectionKey)!
  17. const itemRef = ref<HTMLElement>()
  18. const isActived = computed(() => {
  19. return props.subMenu
  20. ? rootMenu.subMenus[props.uniqueKey.at(-1)!].active
  21. : rootMenu.activeIndex === props.uniqueKey.at(-1)!
  22. })
  23. const isItemActive = computed(() => {
  24. return isActived.value && (!props.subMenu || rootMenu.isMenuPopup)
  25. })
  26. // 缩进样式
  27. const indentStyle = computed(() => {
  28. return !rootMenu.isMenuPopup
  29. ? `padding-left: ${20 * (props.level ?? 0)}px`
  30. : ''
  31. })
  32. defineExpose({
  33. ref: itemRef,
  34. })
  35. </script>
  36. <template>
  37. <div v-if="item.meta?.menu"
  38. ref="itemRef" class="menu-item relative transition-all" :class="{
  39. 'active': isItemActive,
  40. 'py-1 px-2': (rootMenu.isMenuPopup && rootMenu.props.mode === 'vertical') || (rootMenu.isMenuPopup && level !== 0 && rootMenu.props.mode === 'horizontal') || !rootMenu.isMenuPopup,
  41. 'px-1 py-2': rootMenu.isMenuPopup && level === 0 && rootMenu.props.mode === 'horizontal',
  42. }"
  43. >
  44. <router-link v-slot="{ href, navigate }" custom :to="uniqueKey.at(-1) ?? ''">
  45. <HTooltip
  46. :enable="rootMenu.isMenuPopup && level === 0 && !subMenu"
  47. :text="typeof item.meta?.title === 'function' ? item.meta?.title() : item.meta?.title" placement="right"
  48. class="h-full w-full"
  49. >
  50. <component
  51. :is="subMenu ? 'div' : 'a'" v-bind="{
  52. ...(!subMenu && {
  53. href: item.meta?.link ? item.meta.link : href,
  54. target: item.meta?.link ? '_blank' : '_self',
  55. class: 'no-underline',
  56. }),
  57. }"
  58. class="group menu-item-container h-full w-full flex cursor-pointer items-center justify-between gap-1 px-4 py-3 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)])"
  59. :class="{
  60. 'text-[var(--g-sub-sidebar-menu-active-color)]! bg-[var(--g-sub-sidebar-menu-active-bg)]!': isItemActive,
  61. 'px-3!': rootMenu.isMenuPopup && level === 0,
  62. }" :title="typeof item.meta?.title === 'function' ? item.meta?.title() : item.meta?.title" v-on="{
  63. ...(!subMenu && {
  64. click: navigate,
  65. }),
  66. }"
  67. >
  68. <div
  69. class="inline-flex flex-1 items-center justify-center gap-[12px]" :class="{
  70. 'flex-col': rootMenu.isMenuPopup && level === 0 && rootMenu.props.mode === 'vertical',
  71. 'gap-1!': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName,
  72. 'w-full': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName && rootMenu.props.mode === 'vertical',
  73. }" :style="indentStyle"
  74. >
  75. <SvgIcon
  76. v-if="props.item.meta?.icon" :name="props.item.meta.icon" :size="18"
  77. class="menu-item-container-icon transition-transform group-hover-scale-120"
  78. />
  79. <span
  80. v-if="!(rootMenu.isMenuPopup && level === 0 && !rootMenu.props.showCollapseName)"
  81. class="w-0 flex-1 truncate text-sm transition-height transition-opacity transition-width" :class="{
  82. 'opacity-0 w-0 h-0': rootMenu.isMenuPopup && level === 0 && !rootMenu.props.showCollapseName,
  83. 'w-full text-center': rootMenu.isMenuPopup && level === 0 && rootMenu.props.showCollapseName,
  84. }"
  85. >
  86. {{ typeof item.meta?.title === 'function' ? item.meta?.title() : item.meta?.title }}
  87. </span>
  88. </div>
  89. <i
  90. v-if="subMenu && !(rootMenu.isMenuPopup && level === 0)"
  91. 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])"
  92. :class="[
  93. 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])',
  94. rootMenu.isMenuPopup && level === 0 && 'opacity-0',
  95. rootMenu.isMenuPopup && level !== 0 && '-rotate-90 -top-[1.5px]',
  96. ]"
  97. />
  98. </component>
  99. </HTooltip>
  100. </router-link>
  101. </div>
  102. </template>