cl-back-top.uvue 1.7 KB

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