Loading

【vue】dom元素拖拽指令

commonDrag.js:

/**
 * v-commonDrag 弹窗拖拽
 * @params operate {String} 拖拽项的data-drag-name
 * @params move
 */
export const commonDrag = {
  inserted(el, binding) {
    const { operate, move } = binding.value;
    if (typeof binding.value !== 'object') {
      throw new Error('参数错误!');
    }
    if (!move || operate === false || operate === '') return;

    // 获取拖拽内容头部
    const operateElList = el.querySelectorAll(`[data-drag-name="${operate}"]`);

    // 获取拖拽容器
    let dragDom;
    if (move === true) {
      dragDom = el;
    } else {
      dragDom = document.querySelector(`[class*="${move}"]`);
    }
    if (!dragDom || !operateElList?.length) return;

    const containerRect = dragDom.parentNode.getBoundingClientRect();
    let isDragging = false;
    let isInit = false;
    let oldX, oldY;
    let oldTX, oldTY;
    let minLeft, maxLeft, minTop, maxTop;
    const gap = 20; // 与父容器间的间距

    // 鼠标按下事件
    function onMouseDown(e) {
      isDragging = true;
      if (!Array.from(operateElList).includes(e.target)) return;

      e.stopPropagation();
      oldX = e.clientX;
      oldY = e.clientY;
      const { transform } = dragDom.style;
      const oldT = transform.match(/translateX\(([^)]+)px\) translateY\(([^)]+)px\)/);
      oldTX = oldT?.[1] ? Number(oldT?.[1]) : 0;
      oldTY = oldT?.[2] ? Number(oldT?.[2]) : 0;
      if (!isInit) {
        const rect = dragDom.getBoundingClientRect();
        // 边界限制
        minLeft = containerRect.left - rect.left + gap;
        maxLeft = containerRect.right - rect.right - gap;
        minTop = containerRect.top - rect.top + gap;
        maxTop = containerRect.bottom - rect.bottom - gap;
        isInit = true;
      }
      // 添加鼠标移动和释放事件
      document.addEventListener('mousemove', onMouseMove);
      document.addEventListener('mouseup', onMouseUp);
    }

    // 鼠标移动事件
    function onMouseMove(e) {
      if (!isDragging) return;

      const deltL = e.clientX - oldX; // 移动距离
      const deltT = e.clientY - oldY;
      // 计算新的位置
      let newLeft = oldTX + deltL;
      let newTop = oldTY + deltT;
      newLeft = Math.max(minLeft, Math.min(newLeft, maxLeft));
      newTop = Math.max(minTop, Math.min(newTop, maxTop));
      dragDom.style.transform = `translateX(${newLeft}px) translateY(${newTop}px)`;
    }

    // 鼠标释放事件
    function onMouseUp() {
      isDragging = false;
      document.removeEventListener('mousemove', onMouseMove);
      document.removeEventListener('mouseup', onMouseUp);
    }

    // 绑定鼠标按下事件
    dragDom.addEventListener('mousedown', onMouseDown);

    // 存储事件处理器以便在 unbind 时使用
    el._onMouseUp = onMouseUp;
    el._onMouseMove = onMouseMove;
    el._onMouseDown = onMouseDown;
  },
  unbind(el) {
    // 解绑所有事件
    el.removeEventListener('mousedown', el._onMouseDown);
    document.removeEventListener('mousemove', el._onMouseMove);
    document.removeEventListener('mouseup', el._onMouseUp);
  },
};

使用:

 <div  v-commonDrag="{ operate: operateUUid, move: true,draggable:draggable}">
    <div :data-drag-name="operateUUid" />
 </div>
 import {commonDrag} from '@/utils/commonDrag.js'; // 指令插件
 export default {
  directives: {
    commonDrag
  },
  data(){
    operateUUid:1234,// 操作区id
    draggable:true// 是否可拖拽
  },
}
posted @   Ping5-1  阅读(129)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示