复制代码
<template>
<div
ref="draggableElement"
class="draggable-element"
:style="elementStyle"
@mousedown="startDrag"
@touchstart="startDrag"
>
<slot></slot>
</div>
</template>
<script>
import { ref, onMounted, onUnmounted } from 'vue';
export default {
name: 'PressAndDrag',
setup() {
const draggableElement = ref(null);
const isDragging = ref(false);
const startPos = ref({ x: 0, y: 0 });
const currentPos = ref({ x: 0, y: 0 });
const pressTimer = ref(null);
const elementStyle = ref({
position: 'fixed',
left: '100px',
top: '100px',
cursor: 'pointer',
userSelect: 'none',
touchAction: 'none'
});
// 长按开始
const startPress = (event) => {
// 阻止默认行为,防止触摸设备上的滚动等
event.preventDefault();
// 设置定时器,500ms后开始拖动
pressTimer.value = setTimeout(() => {
isDragging.value = true;
// 获取初始位置
const clientX = event.clientX || event.touches[0].clientX;
const clientY = event.clientY || event.touches[0].clientY;
startPos.value = {
x: clientX - currentPos.value.x,
y: clientY - currentPos.value.y
};
}, 500); // 500ms长按时间
};
// 开始拖动(鼠标/触摸按下)
const startDrag = (event) => {
startPress(event);
// 添加移动和结束事件的监听
window.addEventListener('mousemove', handleMove);
window.addEventListener('touchmove', handleMove, { passive: false });
window.addEventListener('mouseup', endDrag);
window.addEventListener('touchend', endDrag);
};
// 处理移动
const handleMove = (event) => {
if (!isDragging.value) return;
event.preventDefault();
const clientX = event.clientX || event.touches[0].clientX;
const clientY = event.clientY || event.touches[0].clientY;
currentPos.value = {
x: clientX - startPos.value.x,
y: clientY - startPos.value.y
};
updatePosition();
};
// 更新元素位置
const updatePosition = () => {
elementStyle.value.left = `${currentPos.value.x}px`;
elementStyle.value.top = `${currentPos.value.y}px`;
};
// 结束拖动
const endDrag = () => {
// 清除长按定时器
if (pressTimer.value) {
clearTimeout(pressTimer.value);
pressTimer.value = null;
}
isDragging.value = false;
// 移除事件监听
window.removeEventListener('mousemove', handleMove);
window.removeEventListener('touchmove', handleMove);
window.removeEventListener('mouseup', endDrag);
window.removeEventListener('touchend', endDrag);
};
// 组件卸载时清理
onUnmounted(() => {
endDrag();
});
return {
draggableElement,
elementStyle,
startDrag,
handleMove,
endDrag
};
}
};
</script>
<style scoped>
.draggable-element {
background-color: #42b983;
padding: 20px;
border-radius: 8px;
color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
</style>