【Vue】vue3 v-draggable 拖拽指令封裝

說明

需求:實現一個拖拽指令,可在父元素區域任意拖拽元素,同時如果傳入的值爲 father,則拖拽的時候以父元素爲拖拽對象

思路:
1、設置需要拖拽的元素爲absolute,其父元素爲relative。
2、鼠標按下(onmousedown)時記錄目標元素當前的 left 和 top 值。
3、鼠標移動(onmousemove)時計算每次移動的橫向距離和縱向距離的變化值,並改變元素的 left 和 top 值
4、鼠標鬆開(onmouseup)時完成一次拖拽

使用:在 Dom 上加上 v-draggable 即可
<div class="dialog-model" v-draggable></div>

代碼

import type { Directive, DirectiveBinding } from 'vue';
interface ElType extends HTMLElement {
  parentNode: any;
}
const draggable: Directive = {
  mounted: function (el: ElType, binding: DirectiveBinding) {
    el.style.cursor = 'move';
    el.style.position = 'absolute';
    el.onmousedown = function (e) {
      let disX = e.pageX - el.offsetLeft;
      let disY = e.pageY - el.offsetTop;

      if (binding.value === 'father') {
        disX = e.pageX - el.parentNode.offsetLeft;
        disY = e.pageY - el.parentNode.offsetTop;
      } else {
        disX = e.pageX - el.offsetLeft;
        disY = e.pageY - el.offsetTop;
      }

      document.onmousemove = function (e) {
        let x = e.pageX - disX;
        let y = e.pageY - disY;
        let maxX;
        let maxY;

        if (binding.value === 'father') {
          maxX =
            el.parentNode.parentNode.offsetWidth - el.parentNode.offsetWidth;
          maxY =
            el.parentNode.parentNode.offsetHeight - el.parentNode.offsetHeight;
        } else {
          maxX = el.parentNode.offsetWidth - el.offsetWidth;
          maxY = el.parentNode.offsetHeight - el.offsetHeight;
        }

        if (x < 0) {
          x = 0;
        } else if (x > maxX) {
          x = maxX;
        }

        if (y < 0) {
          y = 0;
        } else if (y > maxY) {
          y = maxY;
        }

        if (binding.value === 'father') {
          el.parentNode.style.left = x + 'px';
          el.parentNode.style.top = y + 'px';
        } else {
          el.style.left = x + 'px';
          el.style.top = y + 'px';
        }
      };
      document.onmouseup = function () {
        document.onmousemove = document.onmouseup = null;
      };
    };
  },
};
export default draggable;

演示

      <!-- 詳情彈窗 -->
      <transition name="fade">
        <div class="entity-detail-box" v-if="isShowDetail" :style="detailStyle">
          <div v-draggable="'father'" class="drag-mask"></div>
          <div class="closeBtn pointer" @click="() => (isShowDetail = false)">
            關閉
          </div>
          <slot name="detail"></slot>
        </div>
      </transition>

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章