Header.vue 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <script setup lang="ts">
  2. import { computed } from 'vue'
  3. const props = withDefaults(
  4. defineProps<{
  5. title: string
  6. showBack?: boolean
  7. disableDefaultBack?: boolean
  8. }>(),
  9. {
  10. showBack: true,
  11. disableDefaultBack: false,
  12. },
  13. )
  14. const emit = defineEmits<{
  15. (e: 'back'): void
  16. }>()
  17. const router = useRouter()
  18. const nativeSafeArea = useState<{ top: number, bottom: number }>('native-safe-area')
  19. const headerStyle = computed<Partial<Record<string, string>>>(() => {
  20. if (!nativeSafeArea.value) return {}
  21. return {
  22. paddingTop: `${nativeSafeArea.value.top}px`,
  23. height: `calc(44px + ${nativeSafeArea.value.top}px)`,
  24. }
  25. })
  26. const handleBack = () => {
  27. emit('back')
  28. if (props.disableDefaultBack) return
  29. router.back()
  30. }
  31. </script>
  32. <template>
  33. <header
  34. class="common-header"
  35. :style="headerStyle"
  36. >
  37. <button
  38. v-if="props.showBack"
  39. type="button"
  40. class="common-header__back"
  41. @click="handleBack"
  42. >
  43. <van-icon
  44. name="arrow-left"
  45. :size="18"
  46. />
  47. </button>
  48. <div
  49. v-else
  50. class="common-header__spacer"
  51. />
  52. <h1 class="common-header__title">
  53. {{ props.title }}
  54. </h1>
  55. <div class="common-header__spacer">
  56. <slot name="right" />
  57. </div>
  58. </header>
  59. </template>
  60. <style scoped lang="scss">
  61. .common-header {
  62. position: sticky;
  63. top: 0;
  64. z-index: 10;
  65. box-sizing: border-box;
  66. height: calc(44px + env(safe-area-inset-top));
  67. padding-top: env(safe-area-inset-top);
  68. padding: 0 16px;
  69. display: flex;
  70. align-items: center;
  71. justify-content: space-between;
  72. background: #fff;
  73. }
  74. .common-header__back {
  75. border: none;
  76. padding: 4px;
  77. border-radius: 999px;
  78. background: transparent;
  79. display: flex;
  80. align-items: center;
  81. justify-content: center;
  82. }
  83. .common-header__title {
  84. font-size: 18px;
  85. font-weight: 500;
  86. color: #17171a;
  87. }
  88. .common-header__spacer {
  89. width: 24px;
  90. height: 24px;
  91. display: flex;
  92. align-items: center;
  93. justify-content: flex-end;
  94. }
  95. </style>