cl-footer.uvue 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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 { isDark, isHarmony, parsePt, usePage } from "@/cool";
  22. import { computed, getCurrentInstance, nextTick, onMounted, ref, watch } from "vue";
  23. import type { PassThroughProps } from "../../types";
  24. defineOptions({
  25. name: "cl-footer"
  26. });
  27. const props = defineProps({
  28. pt: {
  29. type: Object,
  30. default: () => ({})
  31. },
  32. // 最小高度,小于该高度时,不显示
  33. minHeight: {
  34. type: Number,
  35. default: 30
  36. },
  37. // 监听值,触发更新
  38. vt: {
  39. type: Number,
  40. default: 0
  41. }
  42. });
  43. const { proxy } = getCurrentInstance()!;
  44. const page = usePage();
  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 + page.getSafeAreaHeight("bottom");
  69. })
  70. .exec();
  71. },
  72. isHarmony() ? 50 : 0
  73. );
  74. });
  75. }
  76. onMounted(() => {
  77. watch(
  78. computed(() => props.vt),
  79. () => {
  80. visible.value = true;
  81. getHeight();
  82. },
  83. {
  84. immediate: true
  85. }
  86. );
  87. });
  88. </script>
  89. <style lang="scss" scoped>
  90. .cl-footer {
  91. @apply bg-white;
  92. padding-bottom: env(safe-area-inset-bottom);
  93. &.is-dark {
  94. @apply bg-surface-900;
  95. }
  96. &__content {
  97. @apply px-3 py-3;
  98. }
  99. &-wrapper {
  100. @apply fixed bottom-0 left-0 w-full;
  101. }
  102. }
  103. </style>