cl-footer.uvue 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. <template>
  2. <view class="cl-footer-placeholder" :style="{ height: height + 'px' }" v-if="visible"> </view>
  3. <view class="cl-footer-wrapper" :class="[pt.wrapper?.className]">
  4. <view
  5. class="cl-footer"
  6. :class="[
  7. {
  8. 'is-dark': isDark
  9. },
  10. pt.className
  11. ]"
  12. v-if="visible"
  13. >
  14. <view class="cl-footer__content" :class="[pt.content?.className]">
  15. <slot></slot>
  16. </view>
  17. </view>
  18. </view>
  19. </template>
  20. <script setup lang="ts">
  21. import { getSafeAreaHeight, isDark, isHarmony, parsePt } from "@/cool";
  22. import { computed, getCurrentInstance, nextTick, onMounted, ref, watch } from "vue";
  23. import type { PassThroughProps } from "../../types";
  24. import { clFooterOffset } from "./offset";
  25. defineOptions({
  26. name: "cl-footer"
  27. });
  28. const props = defineProps({
  29. pt: {
  30. type: Object,
  31. default: () => ({})
  32. },
  33. // 最小高度,小于该高度时,不显示
  34. minHeight: {
  35. type: Number,
  36. default: 30
  37. },
  38. // 监听值,触发更新
  39. vt: {
  40. type: Number,
  41. default: 0
  42. }
  43. });
  44. const { proxy } = getCurrentInstance()!;
  45. type PassThrough = {
  46. className?: string;
  47. content?: PassThroughProps;
  48. wrapper?: PassThroughProps;
  49. };
  50. const pt = computed(() => parsePt<PassThrough>(props.pt));
  51. // 内容高度
  52. const height = ref(0);
  53. // 是否显示
  54. const visible = ref(true);
  55. // 获取内容高度
  56. function getHeight() {
  57. nextTick(() => {
  58. setTimeout(
  59. () => {
  60. uni.createSelectorQuery()
  61. .in(proxy)
  62. .select(".cl-footer")
  63. .boundingClientRect((res) => {
  64. // 获取内容高度
  65. const h = Math.floor((res as NodeInfo).height ?? 0);
  66. // 设置高度
  67. height.value = h;
  68. // 如果内容高度大于最小高度,则显示
  69. visible.value = h > props.minHeight + getSafeAreaHeight("bottom");
  70. // 隔离高度
  71. clFooterOffset.set(visible.value ? h : 0);
  72. })
  73. .exec();
  74. },
  75. isHarmony() ? 50 : 0
  76. );
  77. });
  78. }
  79. onMounted(() => {
  80. watch(
  81. computed(() => props.vt),
  82. () => {
  83. visible.value = true;
  84. getHeight();
  85. },
  86. {
  87. immediate: true
  88. }
  89. );
  90. });
  91. </script>
  92. <style lang="scss" scoped>
  93. .cl-footer {
  94. @apply bg-white overflow-visible;
  95. padding-bottom: env(safe-area-inset-bottom);
  96. &.is-dark {
  97. @apply bg-surface-900;
  98. }
  99. &__content {
  100. @apply px-3 py-3 overflow-visible;
  101. }
  102. &-wrapper {
  103. @apply fixed bottom-0 left-0 w-full overflow-visible;
  104. }
  105. }
  106. </style>