自定义APP自定义App数据通讯
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

95 lines
2.1 KiB

<!-- FloatingBall.vue -->
<script setup>
import { ref, computed } from 'vue'
const emit = defineEmits(['click'])
const x = ref(window.innerWidth - 60)
const y = ref(window.innerHeight - 150)
const isDragging = ref(false)
const ballStyle = computed(() => ({
position: 'fixed',
left: `${x.value}px`,
top: `${y.value}px`,
zIndex: 99,
userSelect: 'none',
cursor: isDragging.value ? 'grabbing' : 'grab'
}))
const getPoint = e => (e.touches ? e.touches[0] : e)
let startX = 0, startY = 0, initX = 0, initY = 0
const MOVE_THRESHOLD = 5
function startDrag(e) {
const point = getPoint(e)
startX = point.clientX
startY = point.clientY
initX = x.value
initY = y.value
isDragging.value = false
window.addEventListener('mousemove', onMove, { passive: true })
window.addEventListener('mouseup', onUp)
window.addEventListener('touchmove', onMove, { passive: true })
window.addEventListener('touchend', onUp)
e.preventDefault() // 阻止默认行为(如滚动)
}
function onMove(e) {
const p = getPoint(e)
const dx = p.clientX - startX
const dy = p.clientY - startY
if (!isDragging.value && (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)) {
isDragging.value = true
}
if (isDragging.value) {
x.value = Math.max(0, Math.min(window.innerWidth - 50, initX + dx))
y.value = Math.max(0, Math.min(window.innerHeight - 50, initY + dy))
}
}
function onUp() {
window.removeEventListener('mousemove', onMove)
window.removeEventListener('mouseup', onUp)
window.removeEventListener('touchmove', onMove)
window.removeEventListener('touchend', onUp)
if (!isDragging.value) {
emit('click')
}
isDragging.value = false
}
</script>
<template>
<div
class="float-ball"
:style="ballStyle"
@mousedown="startDrag"
@touchstart="startDrag"
@click.stop
>
<slot>AI</slot>
</div>
</template>
<style scoped>
.float-ball {
width: 50px;
height: 50px;
border-radius: 50%;
background: #409eff;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
</style>