ut-suspension.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <template>
  2. <movable-area class="suspension-area" :style="areaStyle">
  3. <movable-view
  4. class="suspension-view"
  5. direction="all"
  6. :x="x"
  7. :y="y"
  8. :inertia="props.inertia"
  9. :out-of-bounds="true"
  10. :disabled="false"
  11. :scale="false"
  12. :style="{
  13. width: `${props.imageWidth}px`,
  14. height: `${props.imageHeight}px`,
  15. }"
  16. @change="onChange"
  17. @click="handleClick">
  18. <slot />
  19. </movable-view>
  20. </movable-area>
  21. </template>
  22. <script setup lang="ts">
  23. import { ref, onMounted, computed } from 'vue';
  24. // 定义props
  25. interface Props {
  26. imageSrc?: string;
  27. imageWidth?: number; // 使用px单位,不再支持rpx
  28. imageHeight?: number; // 使用px单位,不再支持rpx
  29. x?: number; // x坐标(距离屏幕左边的距离,px单位)
  30. y?: number; // y坐标(距离屏幕顶部的距离,px单位)
  31. inertia?: boolean;
  32. snapThreshold?: number;
  33. bgColor?: string;
  34. borderRadius?: string;
  35. }
  36. const props = withDefaults(defineProps<Props>(), {
  37. imageSrc: '/static/logo.png',
  38. imageWidth: 50, // 默认宽度 50px
  39. imageHeight: 50, // 默认高度 50px
  40. x: 10, // 默认距离左边 10px
  41. y: 200, // 默认距离顶部 200px
  42. inertia: false,
  43. snapThreshold: 30,
  44. bgColor: 'transparent',
  45. borderRadius: '0',
  46. });
  47. // 响应式状态
  48. const x = ref<number>(props.x); // movable-view的x坐标(距离左边)
  49. const y = ref<number>(props.y); // movable-view的y坐标(距离顶部)
  50. // 屏幕尺寸
  51. const screenWidth = ref<number>(0);
  52. const screenHeight = ref<number>(0);
  53. // movable-area 样式
  54. const areaStyle = computed(() => {
  55. return {
  56. width: `${screenWidth.value}px`,
  57. height: `${screenHeight.value}px`,
  58. position: 'fixed',
  59. top: '0',
  60. left: '0',
  61. zIndex: '999',
  62. };
  63. });
  64. // 初始化时获取屏幕尺寸
  65. onMounted(() => {
  66. const systemInfo = uni.getSystemInfoSync();
  67. screenWidth.value = systemInfo.windowWidth;
  68. screenHeight.value = systemInfo.windowHeight;
  69. });
  70. // movable-view 位置变化事件
  71. const onChange = (e: any) => {
  72. // if (e.detail) {
  73. // // 直接更新位置
  74. // x.value = e.detail.x;
  75. // y.value = e.detail.y;
  76. // console.log(x.value, y.value);
  77. // 标记为正在拖动
  78. // isDragging.value = true;
  79. // }
  80. };
  81. // 触摸结束事件(拖动结束)
  82. const onTouchEnd = () => {
  83. // 拖动结束后进行边界检查和吸附
  84. // applyBoundaryAndSnap();
  85. // isDragging.value = false;
  86. };
  87. // 点击事件
  88. const handleClick = () => {
  89. // 触发点击事件
  90. console.log('悬浮按钮被点击', { x: x.value, y: y.value });
  91. };
  92. </script>
  93. <style>
  94. .suspension-area {
  95. /* 移除 pointer-events: none,确保可以正常接收拖动事件 */
  96. pointer-events: none;
  97. }
  98. .suspension-view {
  99. display: flex;
  100. justify-content: center;
  101. align-items: center;
  102. overflow: hidden;
  103. background-color: v-bind('props.bgColor');
  104. border-radius: v-bind('props.borderRadius');
  105. pointer-events: auto;
  106. }
  107. </style>