hldy_app/component/storeroom/components/ball.vue

130 lines
3.9 KiB
Vue
Raw Normal View History

2025-04-10 17:20:44 +08:00
<template>
<!-- 使用 view 作为悬浮球容器通过绑定 style 进行定位 -->
<view class="floating-ball" v-show="isShow"
:style="{ left: ballLeft + 'px', top: ballTop + 'px' }"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@touchcancel="handleTouchEnd">
<image class="floating-ball-img" src="/static/index/caigouqingdan.png" />
</view>
</template>
<script setup>
import { ref, onMounted,defineEmits } from 'vue';
const props = defineProps({
isShow: {
type: Boolean,
required: true,
},
});
const emit = defineEmits(['clickBall'])
// 定义悬浮球尺寸和长按阈值
const ballWidth = 60; // 悬浮球宽度,单位 px与 CSS 中保持一致
const ballHeight = 60; // 悬浮球高度
const longPressThreshold = 300; // 长按时间阈值(毫秒)
// 悬浮球当前位置
const ballLeft = ref(1090);
const ballTop = ref(120);
// 用于判断是否进入拖动状态
const isDragging = ref(false);
// 记录初始按下时坐标以及悬浮球起始位置
let startTouchX = 0;
let startTouchY = 0;
let initialLeft = 0;
let initialTop = 0;
let longPressTimer = null;
// 屏幕尺寸
let windowWidth = 0;
let windowHeight = 0;
onMounted(() => {
// 获取系统信息初始化屏幕宽高uni-app API
const res = uni.getSystemInfoSync();
windowWidth = res.windowWidth;
windowHeight = res.windowHeight;
});
// 触摸开始:记录初始位置,同时启动长按定时器
function handleTouchStart(e) {
const touch = e.touches[0];
startTouchX = touch.clientX;
startTouchY = touch.clientY;
initialLeft = ballLeft.value;
initialTop = ballTop.value;
// 设置定时器,达到长按后进入拖动状态
longPressTimer = setTimeout(() => {
isDragging.value = true;
}, longPressThreshold);
}
// 触摸移动:如果进入拖动状态,则计算新位置,同时限制悬浮球不超出屏幕边界
function handleTouchMove(e) {
// 如果尚未进入拖动状态,且手指移动距离较大,则可以提前进入拖动模式
if (!isDragging.value) {
const touch = e.touches[0];
const deltaX = Math.abs(touch.clientX - startTouchX);
const deltaY = Math.abs(touch.clientY - startTouchY);
if(deltaX > 5 || deltaY > 5){
clearTimeout(longPressTimer);
isDragging.value = true;
}
}
// 正在拖动,更新悬浮球位置
if(isDragging.value){
const touch = e.touches[0];
let newLeft = initialLeft + (touch.clientX - startTouchX);
let newTop = initialTop + (touch.clientY - startTouchY);
// 限制左右边界:不让超出屏幕(计算时需要考虑悬浮球自身尺寸)
newLeft = Math.max(0, Math.min(newLeft, windowWidth - ballWidth));
// 限制上下边界
newTop = Math.max(0, Math.min(newTop, windowHeight - ballHeight));
ballLeft.value = newLeft;
ballTop.value = newTop;
}
}
// 触摸结束或取消:若未进入拖动状态则视为点击,触发点击处理方法;否则结束拖动状态
function handleTouchEnd(e) {
clearTimeout(longPressTimer);
if(isDragging.value){
// 拖动结束后重置状态
isDragging.value = false;
} else {
// 非拖动状态下,触发点击事件
triggerClick();
}
}
// 点击事件处理方法
function triggerClick() {
emit('clickBall')
}
</script>
<style lang="less" scoped>
.floating-ball {
position: fixed;
width: 140rpx;
height: 140rpx;
border-radius: 50%;
background: linear-gradient(to bottom right,#3FBBFE,#A541FF);
border: 2rpx solid #fff;
z-index: 999;
display: flex;
justify-content: center;
align-items: center;
/* 可根据需要添加阴影或其他样式 */
.floating-ball-img{
width: 70rpx;
height: 70rpx;
}
}
</style>