cl-back-top.uvue 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <template>
  2. <view class="cl-back-top-wrapper" :style="{ bottom }" @tap="toTop">
  3. <view
  4. class="cl-back-top"
  5. :class="{
  6. 'is-show': visible
  7. }"
  8. >
  9. <cl-icon name="skip-up-line" color="white" size="25px"></cl-icon>
  10. </view>
  11. </view>
  12. </template>
  13. <script setup lang="ts">
  14. import { getTabBarHeight, hasCustomTabBar, scroller } from "@/cool";
  15. import { computed, onMounted, ref, watch, type PropType } from "vue";
  16. import { usePage } from "../../hooks";
  17. import { clFooterOffset } from "../cl-footer/offset";
  18. defineOptions({
  19. name: "cl-back-top"
  20. });
  21. const props = defineProps({
  22. top: {
  23. type: Number as PropType<number | null>,
  24. default: null
  25. }
  26. });
  27. const emit = defineEmits(["backTop"]);
  28. const { screenHeight } = uni.getWindowInfo();
  29. // cl-page 上下文
  30. const { scrollToTop, onScroll } = usePage();
  31. // 是否显示回到顶部按钮
  32. const visible = ref(false);
  33. // 底部距离
  34. const bottom = computed(() => {
  35. let h = 20;
  36. if (hasCustomTabBar()) {
  37. h += getTabBarHeight();
  38. } else {
  39. h += clFooterOffset.get();
  40. }
  41. return h + "px";
  42. });
  43. // 是否页面滚动
  44. const isPage = computed(() => props.top == null);
  45. // 控制是否显示
  46. function onVisible(top: number) {
  47. visible.value = top > screenHeight - 100;
  48. }
  49. // 回到顶部
  50. function toTop() {
  51. if (isPage.value) {
  52. scrollToTop();
  53. }
  54. emit("backTop");
  55. }
  56. onMounted(() => {
  57. if (isPage.value) {
  58. // 监听页面滚动
  59. onScroll((top) => {
  60. onVisible(top);
  61. });
  62. } else {
  63. // 监听参数变化
  64. watch(
  65. computed(() => props.top!),
  66. (top: number) => {
  67. onVisible(top);
  68. },
  69. {
  70. immediate: true
  71. }
  72. );
  73. }
  74. });
  75. </script>
  76. <style lang="scss" scoped>
  77. .cl-back-top {
  78. @apply flex flex-row items-center justify-center bg-primary-500 rounded-full duration-300;
  79. width: 40px;
  80. height: 40px;
  81. transition-property: transform;
  82. transform: translateX(160rpx);
  83. &.is-show {
  84. transform: translateX(-20px);
  85. }
  86. &-wrapper {
  87. @apply fixed right-0 z-50 overflow-visible;
  88. }
  89. }
  90. </style>