首先明确需要传入组件的属性:
* @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;
}