cl-back-top.uvue 1.8 KB

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