长按拖拽移动的vue3组件

复制代码
<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>

使用示例

复制代码
<template>
  <div class="container">
    <PressAndDrag>
      长按并拖动我
    </PressAndDrag>
  </div>
</template>

<script>
import PressAndDrag from './PressAndDrag.vue';

export default {
  components: {
    PressAndDrag
  }
};
</script>

<style>
.container {
  height: 100vh;
  position: relative;
}
</style>
相关推荐
aixingpan5 分钟前
aixingpan.cn API开发文档:api_docs_bichart_natalvssecondary2接口指南
前端·php
MZ_ZXD00114 分钟前
【关注可白嫖源码】--课程设计--毕业设计-- 29210 Vue.js 3+Springboot中药材基本信息与图片查询系统
javascript·spring boot·课程设计·毕设·大作业·程序开发·毕设代做
liangshanbo121518 分钟前
Webpack Tree Shaking 面试题整理
前端·webpack·node.js
斯内普吖22 分钟前
(开源)水果蔬菜商城实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源
Ai-_Man36 分钟前
您您这可以把Google AI Studio的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑
去伪存真37 分钟前
从乱码到高精度检索:探矿业务中 TXT、Word、PDF 与网页的 RAG 清洗之道
前端·agent
两个西柚呀1 小时前
JS事件总结
前端·javascript·css
小狼154541 小时前
拼多多订单数据导出 CSV 实战:接口分页、字段平铺与 5 个数据坑,多多开票助手
java·前端·javascript
搬砖的小码农_Sky1 小时前
AI Agent:Node.js和浏览器运行环境的本质区别
javascript·node.js·人机交互
ss2731 小时前
AI全栈实战 | 2.2-02 React 思维模型:数据不可变 vs Vue 数据可变,两种哲学把复杂度推给谁
前端·vue.js·react.js