hldy_app/component/storeroom/ball.vue

130 lines
3.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>