Vue自定义组件——封装一个简单的可拖拽的弹出框 可拖拽的Dialog

首先明确需要传入组件的属性:

* @Props: 
    dialogVisible  Number      非0打开
    allowDrag      Boolean     是否可以拖拽
    noFoot         Boolean     是否显示按钮行
    @submit        Function    点击提交按钮的回调
 -->

设计组件的组成部分,这里简单的加了一个遮罩,只有遮罩层和弹窗主体。

用到了h5的drag属性 HTML5 拖放 | 菜鸟教程

组件内部提供了title和connect两个插槽供使用。

插槽?插槽 — Vue.js

弹窗使用绝对定位供捕获鼠标位置后计算拖拽终点。

<template>
  <div class="dialog">
    <!-- 遮罩层 -->
    <div class="logOn" @click="showModal = 0" v-show="showModal" />
    <!-- 弹窗本体 -->
    <div
      class="modalOn"
      v-show="showModal"
      :draggable="allowDrag"
      @dragstart="dragstart"
      @dragend="dragend"
      ref="modal"
      :style="{ top: top + 'px', left: left + 'px' }"
    >
      <div class="head">
        <div>
          <slot name="title" />
        </div>
        <div @click="showModal = 0" class="x">×</div>
      </div>
      <div class="main">
        <slot name="connect" />
      </div>
      <!-- 底部按钮行 -->
      <div class="but_line" v-show="!noFoot">
        <el-button class="but" @click="showModal = 0">取消</el-button>
        <el-button class="but" type="primary" @click="submit"> 提交 </el-button>
      </div>
    </div>
  </div>
</template>

功能实现:dragstart可以获取到拖拽时鼠标相对于弹窗的位置坐标,dragend获得的拖拽后鼠标位置减去鼠标相对于弹窗的位置就是弹窗拖拽的实际位置。

这里用e.preventDefault()阻止了拖拽弹窗时的禁止放置图标

用e.dataTransfer.dropEffect = "move" 重新定义了拖拽时的可移动图标

什么是dataTransfer.dropEffect?  

DataTransfer.dropEffect - Web API 接口参考 | MDN

<script type="text/ecmascript-6">
export default {
  name: "dragModal",
  components: {},
  data() {
    return {
      showModal: 0, //是否打开弹窗 非0打开
      left: "",
      top: "",
    };
  },
  props: {
    //父组件传入的弹窗开关状态 非0打开
    dialogVisible: {
      type: Number,
      default: 0,
    },
    //是否能拖拽
    allowDrag: {
      type: Boolean,
      default: false,
    },
    //是否显示按钮行
    noFoot: {
      type: Boolean,
      default: false,
    },
  },
  mounted() {},
  computed: {},
  watch: {
    //监听父组件弹窗开关状态同步至组件
    dialogVisible() {
      this.showModal = this.dialogVisible;
    },
  },
  methods: {
    /**
     * @description: 拖拽前的回调
     * @param {Object} DragEvent
     * @return void
     */
    dragstart(e) {
      document.ondragover = function (e) {
        e.preventDefault();
        e.dataTransfer.dropEffect = "move";
      };
      //获取鼠标相对于拖拽元素的位置
      this.diffX = e.layerX;
      this.diffY = e.layerY;
    },
    /**
     * @description: 拖拽后的回调
     * @param {Object} DragEvent
     * @return void
     */
    dragend(e) {
      document.ondragover = function (e) {
        e.dataTransfer.dropEffect = "none";
      };
      //获取元素落点位置 鼠标位置-相对于拖拽元素的位置
      this.top = e.pageY - this.diffY;
      this.left = e.pageX - this.diffX;
    },
    submit() {
      this.$emit("submit");
    },
  },
};
</script>

一些简单的居中样式和类似el的遮罩样式

.dialog {
  display: flex;
  align-items: center;
  justify-content: center;
}

.logOn {
  background: rgba(0, 0, 0, 0.3);
  height: 100%;
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}

.modalOn {
  min-width: 600px;
  background: #fff;
  position: absolute;
  border-radius: 3px;
  padding: 12px;
}

.head {
  display: flex;
  justify-content: space-between;
  border-bottom: 1px solid #e6e6e6;
  height: 30px;
}
.x {
  width: 30px;
  display: flex;
  justify-content: center;
  cursor: pointer;
}
.main {
  padding: 12px;
}

.but {
  border-radius: 5px;
  height: 30px;
  line-height: 6px;
}

.but_line {
  display: flex;
  justify-content: flex-end;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值