說明
需求:實現一個拖拽指令,可在父元素區域任意拖拽元素,同時如果傳入的值爲 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>