liveh5-nuxt/app/components/drag-window/index.vue

119 lines
2.8 KiB
Vue
Raw Normal View History

<template>
<div
class="draggable-container"
:style="containerStyle"
@mousedown="startDrag"
@touchstart.prevent="startDrag"
>
<slot />
</div>
</template>
<script setup>
const props = defineProps({
fixedSide: {
type: String,
default: 'none',
validator: (v) => ['left', 'right', 'top', 'bottom', 'none'].includes(v)
},
initialPosition: {
type: Object,
default: () => ({ x: 0, y: 0 })
},
width: Number,
height: Number
})
const position = ref({ ...props.initialPosition })
const isDragging = ref(false)
const startPosition = ref({ x: 0, y: 0 })
const containerStyle = computed(() => ({
position: 'fixed',
width: props.width ? `${props.width}px` : 'auto',
height: props.height ? `${props.height}px` : 'auto',
left: `${position.value.x}px`,
top: `${position.value.y}px`,
cursor: isDragging.value ? 'grabbing' : 'grab'
}))
const getClientPos = (e) => ({
x: e.touches ? e.touches[0].clientX : e.clientX,
y: e.touches ? e.touches[0].clientY : e.clientY
})
const startDrag = (e) => {
isDragging.value = true
const { x, y } = getClientPos(e)
startPosition.value = {
x: x - position.value.x,
y: y - position.value.y
}
}
const onDrag = (e) => {
if (!isDragging.value) return
const { x: clientX, y: clientY } = getClientPos(e)
const maxX = window.innerWidth - (props.width || 0)
const maxY = window.innerHeight - (props.height || 0)
let newX = clientX - startPosition.value.x
let newY = clientY - startPosition.value.y
// 根据固定边限制移动方向
switch (props.fixedSide) {
case 'left':
newX = 0
newY = Math.max(0, Math.min(newY, maxY))
break
case 'right':
newX = maxX
newY = Math.max(0, Math.min(newY, maxY))
break
case 'top':
newX = Math.max(0, Math.min(newX, maxX))
newY = 0
break
case 'bottom':
newX = Math.max(0, Math.min(newX, maxX))
newY = maxY
break
default:
newX = Math.max(0, Math.min(newX, maxX))
newY = Math.max(0, Math.min(newY, maxY))
}
position.value = {
x: ['top', 'bottom', 'none'].includes(props.fixedSide) ? newX : position.value.x,
y: ['left', 'right', 'none'].includes(props.fixedSide) ? newY : position.value.y
}
}
const stopDrag = () => {
isDragging.value = false
}
// 事件监听
onMounted(() => {
document.addEventListener('mousemove', onDrag)
document.addEventListener('mouseup', stopDrag)
document.addEventListener('touchmove', onDrag)
document.addEventListener('touchend', stopDrag)
})
onUnmounted(() => {
document.removeEventListener('mousemove', onDrag)
document.removeEventListener('mouseup', stopDrag)
document.removeEventListener('touchmove', onDrag)
document.removeEventListener('touchend', stopDrag)
})
</script>
<style scoped>
.draggable-container {
touch-action: none;
user-select: none;
z-index: 9999;
}
</style>