cl-footer.uvue 2.1 KB

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