cl-back-top.uvue 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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, onUnmounted, 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, offScroll } = 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(onVisible);
  60. } else {
  61. // 监听参数变化
  62. watch(
  63. computed(() => props.top!),
  64. (top: number) => {
  65. onVisible(top);
  66. },
  67. {
  68. immediate: true
  69. }
  70. );
  71. }
  72. });
  73. onUnmounted(() => {
  74. if (isPage.value) {
  75. offScroll(onVisible);
  76. }
  77. });
  78. </script>
  79. <style lang="scss" scoped>
  80. .cl-back-top {
  81. @apply flex flex-row items-center justify-center bg-primary-500 rounded-full duration-300;
  82. width: 40px;
  83. height: 40px;
  84. transition-property: transform;
  85. transform: translateX(160rpx);
  86. &.is-show {
  87. transform: translateX(-20px);
  88. }
  89. &-wrapper {
  90. @apply fixed right-0 z-50 overflow-visible;
  91. }
  92. }
  93. </style>