Files
tool-tech-front/src/components/FileUpload/sgDragMove.vue
2024-09-18 11:31:25 +08:00

256 lines
8.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div :class="$options.name"></div>
</template>
<script>
export default {
name: "sgDragMove",
data() {
return {
offset: { x: 0, y: 0 }, //偏移量
style: { top: "0px", left: "0px" },
canDragDom: null, //触发拖拽事件的物体
moveDom: null, //可以移动的物体
};
},
props: [
"data", //可以被拖拽的元素数组(必选)
/* data格式说明
[
...
{
canDragDom: elementDOM,//可以拖拽的位置元素数组or单个元素
moveDom: elementDOM,//拖拽同步移动的元素数组or单个元素
},
...
]
*/
"disabled", //屏蔽
"mousedownNearSide", //按下鼠标吸附边界
"mousemoveNearSide", //移动鼠标吸附边界
"mouseupNearSide", //弹起鼠标吸附边界
"nearPadding", //距离边界多少像素自动吸附mousedownNearSide||mousemoveNearSide||mouseupNearSide=true的时候才能生效值可以是number或array类型例如是5代表[5,5,5,5],其中数组以此代表[上,右,下,左]
"stopBoundary", //停靠边界距离移动物体将按照这个值作为界限不再移出该范围mousedownNearSide||mousemoveNearSide||mouseupNearSide=true的时候才能生效值可以是number或array类型例如是5代表[5,5,5,5],其中数组以此代表[上,右,下,左]
"cursor", //鼠标样式
/*cursor格式说明{
grab:'default',//移入可拖拽区域的鼠标样式
grabbing:'default',//拖拽过程中鼠标样式
} */
],
watch: {
data: {
handler(newValue, oldValue) {
newValue ? this.__addDragsEvents(newValue) : this.__removeDragsEvents(oldValue);
},
deep: true,
immediate: true,
},
disabled: {
handler(newValue, oldValue) {
newValue ? this.__removeAllEvents() : this.__addAllEvents();
},
deep: true,
immediate: true,
},
style: {
handler(newValue, oldValue) {
if (this.moveDom && newValue && Object.keys(newValue).length) {
let d = newValue;
Object.keys(d).forEach((k) => (this.moveDom.style[k] = d[k]));
this.moveDom.style.right = "revert";
this.moveDom.style.bottom = "revert";
this.$emit(`getStyle`, d); //用这个方式抛出被移动物体的位置数据解决多处修改同一DOM属性导致的冲突问题
}
},
deep: true, //深度监听
immediate: true, //立即执行
},
},
destroyed() {
this.__removeAllEvents();
},
mounted() {
this.$parent.$el.style.setProperty(
"--sgDragMove-grab",
(this.cursor || {}).grab || "grab"
); //js往css传递局部参数
this.$parent.$el.style.setProperty(
"--sgDragMove-grabbing",
(this.cursor || {}).grabbing || "grabbing"
); //js往css传递局部参数
},
methods: {
__addAllEvents() {
this.__addDragsEvents(this.data);
},
__removeAllEvents() {
this.__removeWindowEvents();
this.__removeDragsEvents(this.data);
},
__addWindowEvents() {
this.__removeWindowEvents();
addEventListener("mousemove", this.mousemove_window);
addEventListener("mouseup", this.mouseup_window);
},
__removeWindowEvents() {
removeEventListener("mousemove", this.mousemove_window);
removeEventListener("mouseup", this.mouseup_window);
},
// 初始化需要拖拽的DIV
__addDragsEvents(doms) {
(doms || []).forEach((dom) => {
this.__removeDraggedEvents(dom.canDragDom);
this.__addDraggedEvents(dom.canDragDom);
});
},
__removeDragsEvents(doms) {
(doms || []).forEach((dom) => {
this.__removeDraggedEvents(dom.canDragDom);
});
},
__addDraggedEvents(dom) {
dom.setAttribute("sgDragMove_grab", "ready");
dom.addEventListener("dragstart", this.dragstart);
dom.addEventListener("mousedown", this.mousedown);
},
__removeDraggedEvents(dom) {
dom.removeEventListener("dragstart", this.dragstart);
dom.removeEventListener("mousedown", this.mousedown);
},
dragstart(e) {
e.stopPropagation();
e.preventDefault();
return false;
},
mousedown(e) {
if (this.disabled) return this.mouseup_window(e);
if (e.button === 2) return this.mouseup_window(e); //点击了鼠标右键
this.canDragDom = e.currentTarget;
this.moveDom = this.data.find((v) => v.canDragDom == this.canDragDom).moveDom;
this.canDragDom.setAttribute("sgDragMove_grab", "down");
this.moveDom.setAttribute("sgDragMove_move", "ready");
let or = this.moveDom.getBoundingClientRect();
this.offset = { x: e.clientX - or.x, y: e.clientY - or.y };
(this.mousedownNearSide || this.mousedownNearSide === "") && this.nearSide();
this.$emit("dragStart", this.getResult(e));
this.__addWindowEvents();
},
setOffset(d) {
this.offset = {
...this.offset,
...d,
};
},
mousemove_window(e) {
this.canDragDom.setAttribute("sgDragMove_grab", "down");
this.moveDom.setAttribute("sgDragMove_move", "ing");
let x = e.clientX - this.offset.x;
let y = e.clientY - this.offset.y;
this.style = { left: x + "px", top: y + "px" };
this.style["transition-property"] = "left,top";
this.style["transition-duration"] = "0s,0s";
this.$nextTick(() => {
(this.mousemoveNearSide || this.mousemoveNearSide === "") && this.nearSide();
this.$emit("dragging", this.getResult(e));
});
},
mouseup_window(e) {
this.$emit("dragEnd", this.getResult(e));
(this.mouseupNearSide || this.mouseupNearSide === "") && this.nearSide();
this.offset = null;
this.style = null;
this.canDragDom.setAttribute("sgDragMove_grab", "ready");
this.moveDom.setAttribute("sgDragMove_move", "end");
setTimeout(() => {
this.moveDom && this.moveDom.removeAttribute("sgDragMove_move");
}, 100);
this.canDragDom = null;
this.moveDom = null;
this.__removeWindowEvents();
},
// 自动吸附网页边界
nearSide() {
let arr = this.nearPadding ? JSON.parse(JSON.stringify(this.nearPadding)) : 0;
Array.isArray(arr) || (arr = [...Array(4)].map((v) => arr));
let [dis_top, dis_right, dis_bottom, dis_left] = arr;
arr = this.stopBoundary ? JSON.parse(JSON.stringify(this.stopBoundary)) : 0;
Array.isArray(arr) || (arr = [...Array(4)].map((v) => arr));
let [
stopBoundary_top,
stopBoundary_right,
stopBoundary_bottom,
stopBoundary_left,
] = arr;
let x = parseFloat(this.moveDom.style.left);
let y = parseFloat(this.moveDom.style.top);
let rect = this.moveDom.getBoundingClientRect();
let min_side_x = 0,
min_x = min_side_x + dis_left,
min_left = min_side_x + stopBoundary_left;
let min_side_y = 0,
min_y = min_side_y + dis_top,
min_top = min_side_y + stopBoundary_top;
x < min_x && (this.moveDom.style.left = `${min_left}px`);
y < min_y && (this.moveDom.style.top = `${min_top}px`);
let max_side_x = innerWidth - rect.width,
max_x = max_side_x - dis_right,
max_right = max_side_x - stopBoundary_right;
let max_side_y = innerHeight - rect.height,
max_y = max_side_y - dis_bottom,
max_bottom = max_side_y - stopBoundary_bottom;
x > max_x && (this.moveDom.style.left = `${max_right}px`);
y > max_y && (this.moveDom.style.top = `${max_bottom}px`);
},
getResult(e) {
return {
$event: e,
canDragDom: this.canDragDom,
moveDom: this.moveDom,
canDragDomRect: this.canDragDom ? this.canDragDom.getBoundingClientRect() : null,
moveDomRect: this.moveDom ? this.moveDom.getBoundingClientRect() : null,
};
},
},
};
</script>
<style lang="scss" scoped>
[sgDragMove_grab="ready"] {
cursor: var(--sgDragMove-grab); //css获取js传递的参数
* {
cursor: var(--sgDragMove-grab); //css获取js传递的参数
}
&:hover {
opacity: 1;
}
&:active {
opacity: 0.9;
}
}
[sgDragMove_grab="down"] {
cursor: var(--sgDragMove-grabbing); //css获取js传递的参数
* {
cursor: var(--sgDragMove-grabbing); //css获取js传递的参数
}
}
[sgDragMove_move="ready"] {
opacity: 1;
}
[sgDragMove_move="ing"] {
opacity: 0.9;
}
[sgDragMove_move="end"] {
transition: 0.1s;
}
</style>