layout-header.vue 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. <script setup lang="ts">
  2. import type { CSSProperties } from 'vue';
  3. import { computed, useSlots } from 'vue';
  4. import { Menu } from '@vben-core/icons';
  5. import { VbenIconButton } from '@vben-core/shadcn-ui';
  6. interface Props {
  7. /**
  8. * 横屏
  9. * @default false
  10. */
  11. fullWidth?: boolean;
  12. /**
  13. * 高度
  14. * @default 60
  15. */
  16. height?: number;
  17. /**
  18. * 是否混合导航
  19. * @default false
  20. */
  21. isMixedNav?: boolean;
  22. /**
  23. * 是否移动端
  24. * @default false
  25. */
  26. isMobile?: boolean;
  27. /**
  28. * 是否显示
  29. * @default true
  30. */
  31. show?: boolean;
  32. /**
  33. * 是否显示关闭菜单按钮
  34. * @default true
  35. */
  36. showToggleBtn?: boolean;
  37. /**
  38. * 侧边菜单宽度
  39. * @default 0
  40. */
  41. sidebarWidth?: number;
  42. /**
  43. * 宽度
  44. * @default 100%
  45. */
  46. width?: string;
  47. /**
  48. * zIndex
  49. * @default 0
  50. */
  51. zIndex?: number;
  52. }
  53. const props = withDefaults(defineProps<Props>(), {
  54. height: 60,
  55. isMixedNav: false,
  56. show: true,
  57. showToggleBtn: false,
  58. sidebarWidth: 0,
  59. width: '100%',
  60. zIndex: 0,
  61. });
  62. const emit = defineEmits<{ openMenu: []; toggleSidebar: [] }>();
  63. const slots = useSlots();
  64. const style = computed((): CSSProperties => {
  65. const { fullWidth, height, show } = props;
  66. const right = !show || !fullWidth ? undefined : 0;
  67. return {
  68. // ...(props.isMixedNav ? { left: 0, position: `fixed` } : {}),
  69. height: `${height}px`,
  70. marginTop: show ? 0 : `-${height}px`,
  71. right,
  72. };
  73. });
  74. const logoStyle = computed((): CSSProperties => {
  75. return {
  76. minWidth: `${props.isMobile ? 40 : props.sidebarWidth}px`,
  77. };
  78. });
  79. function handleToggleMenu() {
  80. if (props.isMobile) {
  81. emit('openMenu');
  82. } else {
  83. emit('toggleSidebar');
  84. }
  85. }
  86. </script>
  87. <template>
  88. <header
  89. :style="style"
  90. class="border-border bg-background top-0 flex w-full flex-[0_0_auto] items-center border-b transition-[margin-top] duration-200"
  91. >
  92. <div v-if="slots.logo" :style="logoStyle">
  93. <slot name="logo"></slot>
  94. </div>
  95. <VbenIconButton
  96. v-if="showToggleBtn || isMobile"
  97. class="my-0 ml-2 mr-1 rounded"
  98. @click="handleToggleMenu"
  99. >
  100. <Menu class="size-4" />
  101. </VbenIconButton>
  102. <slot></slot>
  103. </header>
  104. </template>