136 lines
4.2 KiB
TypeScript
136 lines
4.2 KiB
TypeScript
/**
|
||
* 指令,仅用于element-plus 中的 dialog 使用
|
||
* 可基于窗口各种拖拽使用
|
||
*/
|
||
import type { Directive } from "vue";
|
||
interface ElType extends HTMLDivElement {
|
||
__mouseDown__: any;
|
||
__mouseUp__: any;
|
||
__mouseMove__: any;
|
||
__sizeChange__: any;
|
||
}
|
||
const drag: Directive = {
|
||
mounted(el: ElType) {
|
||
const dialog = el.querySelector(".el-dialog") as HTMLElement;
|
||
const header = el.querySelector(".el-dialog__header") as HTMLElement;
|
||
console.log(el)
|
||
const dialogMask = el.querySelector(".el-overlay") as HTMLElement;
|
||
dialogMask.style.cssText += "overflow: hidden;";
|
||
header.style.cursor = "move";
|
||
let dragStatus = false;
|
||
const data = {
|
||
// 数据源,不变部分为:window信息、dialog信息、mouse初始值信息,可变部分为:拖拽坐标位移
|
||
window: {
|
||
// window信息
|
||
width: 0,
|
||
height: 0,
|
||
},
|
||
dialog: {
|
||
x: 0,
|
||
y: 0,
|
||
width: 0,
|
||
height: 0,
|
||
marginTop: "",
|
||
}, // dialog信息
|
||
mouse: {
|
||
// 鼠标初始信息
|
||
x: 0,
|
||
y: 0,
|
||
},
|
||
drag: {
|
||
// 拖拽过程信息
|
||
x: 0,
|
||
y: 0,
|
||
},
|
||
};
|
||
// 所有的监听只为了修改data数据
|
||
header.addEventListener("mousedown", mouseDown);
|
||
document.addEventListener("mousemove", mouseMove);
|
||
document.addEventListener("mouseup", mouseUp);
|
||
window.addEventListener("resize", sizeChange);
|
||
// 边界处理,防止拖动位置溢出
|
||
function handlePosition() {
|
||
if (data.mouse.x - data.drag.x >= data.dialog.x) {
|
||
data.drag.x = data.mouse.x - data.dialog.x;
|
||
}
|
||
if (
|
||
data.drag.x - data.mouse.x >=
|
||
data.window.width - (data.dialog.x + data.dialog.width)
|
||
) {
|
||
data.drag.x =
|
||
data.mouse.x + data.window.width - data.dialog.x - data.dialog.width;
|
||
}
|
||
if (data.mouse.y - data.drag.y >= data.dialog.y) {
|
||
data.drag.y = data.mouse.y - data.dialog.y;
|
||
}
|
||
if (
|
||
data.drag.y - data.mouse.y >=
|
||
data.window.height - (data.dialog.y + data.dialog.height)
|
||
) {
|
||
data.drag.y =
|
||
data.mouse.y +
|
||
data.window.height -
|
||
data.dialog.y -
|
||
data.dialog.height;
|
||
}
|
||
setPosition();
|
||
}
|
||
// 根据data来设置拖动后的位置
|
||
function setPosition() {
|
||
const top = data.drag.y - data.mouse.y + data.dialog.y;
|
||
const left = data.drag.x - data.mouse.x + data.dialog.x;
|
||
dialog.style.cssText += `position: absolute; top: calc(${top}px - ${data.dialog.marginTop}); left: ${left}px;`;
|
||
}
|
||
function mouseDown(e: any) {
|
||
// 获取dialog目前的位置,坐标, 以及屏幕当前的宽高
|
||
// 一切初始数据的获取应该放置于此,避免其他如:宽度修改等一系列的影响
|
||
if (e.button !== 0) {
|
||
return;
|
||
}
|
||
data.window = {
|
||
width: document.body.clientWidth,
|
||
height: document.body.clientHeight,
|
||
};
|
||
data.dialog = dialog.getBoundingClientRect();
|
||
data.dialog.marginTop = dialog.style.marginTop;
|
||
data.mouse = {
|
||
x: e.clientX,
|
||
y: e.clientY,
|
||
};
|
||
dragStatus = true;
|
||
}
|
||
function mouseMove(e: any) {
|
||
if (dragStatus) {
|
||
data.drag = {
|
||
x: e.clientX,
|
||
y: e.clientY,
|
||
};
|
||
dialogMask.style.userSelect = "none";
|
||
handlePosition();
|
||
}
|
||
}
|
||
function mouseUp(e: any) {
|
||
dialogMask.style.userSelect = "auto";
|
||
dragStatus = false;
|
||
}
|
||
function sizeChange(e: any) {
|
||
// dialog.style.cssText += 'position: static';
|
||
}
|
||
// 方便卸载使用
|
||
el.__mouseDown__ = mouseDown;
|
||
el.__mouseUp__ = mouseUp;
|
||
el.__mouseMove__ = mouseMove;
|
||
el.__sizeChange__ = sizeChange;
|
||
},
|
||
beforeUnmount(el: ElType) {
|
||
// 避免重复开销,卸载所有的监听
|
||
// 解决问题:多次创建新的实例 =》 监听不取消 =》 同时存在多个无用的监听,导致页面卡顿
|
||
document.removeEventListener("mousedown", el.__mouseDown__);
|
||
document.removeEventListener("mousemove", el.__mouseMove__);
|
||
document.removeEventListener("mouseup", el.__mouseUp__);
|
||
window.removeEventListener("resize", el.__sizeChange__);
|
||
},
|
||
};
|
||
|
||
export default drag;
|