vue3 自定义拖拽指令(德芙一般丝滑)

文章最后会有全部代码

看这里,了解vue提供的自定义指令包含的钩子函数

  1. 当使用自定义指令时,钩子函数可以获取到当前指令所绑定的dom
  2. 当在组件上使用自定义指令时,它会始终应用于组件的根节点!

元素可以拖动,也就是说元素的位置发生变化,发生变化的方式要么是利用定位改变元素的left、top属性,要么利用transform改变元素的偏移量。在此之上进行对鼠标事件的监听便可,用到的鼠标事件:

  1. mousedown事件,记录元素初始偏移位置;
  2. mousemove事件,根据鼠标位移向量修改元素的偏移位置;
  3. mouseup事件,重置数据。

 

 

 

创建拖拽指令

const drag ={
    mounted(el, binding){
        // el->当前dom元素
        // binding-> 可选参数对象
    }
}

添加鼠标监听

 const onMouseDown = (e) => {
        e.stopPropagation();
        startPosition = getPosition(e);
        if (outerElement && element) {
          const outerElementRect = outerElement.getBoundingClientRect();
          const elementRect = element.getBoundingClientRect();
          draggingMoveVectorRange = [outerElementRect.top - elementRect.top, outerElementRect.bottom - elementRect.bottom, outerElementRect.left - elementRect.left, outerElementRect.right - elementRect.right];
        }
      };
      const onMouseMove = (e) => {
        if (startPosition && draggingMoveVectorRange) {
          endPosition = getPosition(e);
          const currentMoveVector = formatV(minusV(startPosition, endPosition), draggingMoveVectorRange);
          draggingMoveVector = addV(draggedMoveVector, currentMoveVector);
          element.style.transform = setTranslatePosition(startTransform, draggingMoveVector);
        }
      };
      const onMouseUp = (e) => {
        if (startPosition && draggingMoveVectorRange) {
          draggedMoveVector = draggingMoveVector;
        }
        startPosition = null;
      };

全部代码:

export const drag = {
  mounted(el, binding) {
    const addV = (v1, v2) => {
      const x = v1[0] + v2[0];
      const y = v1[1] + v2[1];
      return [x, y];
    };
    const minusV = (v1, v2) => {
      const x = v2[0] - v1[0];
      const y = v2[1] - v1[1];
      return [x, y];
    };
    const formatV = (v, range) => {
      let x = v[0];
      let y = v[1];
      x = Math.max(x, range[2]);
      x = Math.min(x, range[3]);
      y = Math.max(y, range[0]);
      y = Math.min(y, range[1]);
      return [x, y];
    };
    const setTranslatePosition = (transform, v) => {
      return `translate(${v[0]}px, ${v[1]}px)`;
    };
    const getPosition = (e) => {
      if (e instanceof MouseEvent) {
        return [e.pageX, e.pageY];
      }
      const touch = e.touches[0];
      return [touch.pageX, touch.pageY];
    };
    const enableDrag = (element) => {
      let { outerElement, innerElement } = {};
      let startTransform = window.getComputedStyle(element).transform;
      let startPosition = null;
      let endPosition = null;
      let draggingMoveVectorRange = null;
      let draggedMoveVector = [0, 0];
      let draggingMoveVector = [0, 0];
      outerElement = document.body;
      innerElement = element;
      const onMouseDown = (e) => {
        e.stopPropagation();
        startPosition = getPosition(e);
        if (outerElement && element) {
          const outerElementRect = outerElement.getBoundingClientRect();
          const elementRect = element.getBoundingClientRect();
          draggingMoveVectorRange = [outerElementRect.top - elementRect.top, outerElementRect.bottom - elementRect.bottom, outerElementRect.left - elementRect.left, outerElementRect.right - elementRect.right];
        }
      };
      const onMouseMove = (e) => {
        if (startPosition && draggingMoveVectorRange) {
          endPosition = getPosition(e);
          const currentMoveVector = formatV(minusV(startPosition, endPosition), draggingMoveVectorRange);
          draggingMoveVector = addV(draggedMoveVector, currentMoveVector);
          element.style.transform = setTranslatePosition(startTransform, draggingMoveVector);
        }
      };
      const onMouseUp = (e) => {
        if (startPosition && draggingMoveVectorRange) {
          draggedMoveVector = draggingMoveVector;
        }
        startPosition = null;
      };
      const addEventListener = () => {
        if (innerElement) {
          innerElement.addEventListener("mousedown", onMouseDown);
          document.addEventListener("mousemove", onMouseMove);
          document.addEventListener("mouseup", onMouseUp);
        }
      };
      const removeEventListener = () => {
        if (innerElement) {
          innerElement.removeEventListener("mousedown", onMouseDown);
          document.removeEventListener("mousemove", onMouseMove);
          document.removeEventListener("mouseup", onMouseUp);
        }
      };
      addEventListener();
      return removeEventListener;
    };
    enableDrag(el);
  },
  unmounted(el, binding, vnode, prevVnode) {
    // el.removeEventListener("mousedown", onMousedown);
  },
};

注册为全局的指令后在需要的元素上声明v-drag 指令:

 <div  v-drag>
      <span>这是一个可以被拖动的元素</span>        
  </div>

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁锅炖大鹅(e)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值