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