cl-footer.uvue 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <template>
  2. <view class="cl-footer-placeholder" :style="{ height: height + 'px' }" v-if="visible"> </view>
  3. <view class="cl-footer-wrapper">
  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. };
  49. const pt = computed(() => parsePt<PassThrough>(props.pt));
  50. // 内容高度
  51. const height = ref(0);
  52. // 是否显示
  53. const visible = ref(true);
  54. // 获取内容高度
  55. function getHeight() {
  56. nextTick(() => {
  57. setTimeout(
  58. () => {
  59. uni.createSelectorQuery()
  60. .in(proxy)
  61. .select(".cl-footer")
  62. .boundingClientRect((res) => {
  63. // 获取内容高度
  64. const h = Math.floor((res as NodeInfo).height ?? 0);
  65. // 设置高度
  66. height.value = h;
  67. // 如果内容高度大于最小高度,则显示
  68. visible.value = h > props.minHeight + getSafeAreaHeight("bottom");
  69. // 隔离高度
  70. clFooterOffset.set(visible.value ? h : 0);
  71. })
  72. .exec();
  73. },
  74. isHarmony() ? 50 : 0
  75. );
  76. });
  77. }
  78. onMounted(() => {
  79. watch(
  80. computed(() => props.vt),
  81. () => {
  82. visible.value = true;
  83. getHeight();
  84. },
  85. {
  86. immediate: true
  87. }
  88. );
  89. });
  90. </script>
  91. <style lang="scss" scoped>
  92. .cl-footer {
  93. @apply bg-white;
  94. padding-bottom: env(safe-area-inset-bottom);
  95. &.is-dark {
  96. @apply bg-surface-900;
  97. }
  98. &__content {
  99. @apply px-3 py-3;
  100. }
  101. &-wrapper {
  102. @apply fixed bottom-0 left-0 w-full;
  103. }
  104. }
  105. </style>