dootask/resources/assets/js/components/DragBallComponent.vue
2021-09-21 00:26:29 +08:00

260 lines
8.3 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 ref="floatDrag" :style="dragStyle" @mousedown.stop.prevent="mouseDown">
<slot></slot>
</div>
</template>
<script>
export default {
name: "DragBallComponent",
props: {
id: {
type: String,
default: ""
},
distanceLeft: {
type: Number,
default: -1 // 大于 -1 时 distanceRight 无效
},
distanceRight: {
type: Number,
default: 0
},
distanceTop: {
type: Number,
default: -1 // 大于 -1 时 distanceBottom 无效
},
distanceBottom: {
type: Number,
default: 100
},
isScrollHidden: {
type: Boolean,
default: false
},
isCanDraggable: {
type: Boolean,
default: true
},
zIndex: {
type: Number,
default: 50
}
},
data() {
return {
clientWidth: null,
clientHeight: null,
top: 0,
left: 0,
timer: null,
currentTop: 0,
isMoving: false,
record: {}
};
},
created() {
this.clientWidth = document.documentElement.clientWidth;
this.clientHeight = document.documentElement.clientHeight;
},
mounted() {
if (this.id) {
if (!$A.isJson(window._DragBallComponent)) {
window._DragBallComponent = {};
}
}
if (this.isCanDraggable) {
this.$nextTick(() => {
if (this.id && $A.isJson(window._DragBallComponent[this.id])) {
this.left = window._DragBallComponent[this.id].left
this.top = window._DragBallComponent[this.id].top
} else {
if (this.distanceLeft > -1) {
this.left = this.distanceLeft;
} else {
this.left = this.clientWidth - this.floatDrag.offsetWidth - this.distanceRight;
}
if (this.distanceTop > -1) {
this.top = this.distanceTop;
} else {
this.top = this.clientHeight - this.floatDrag.offsetHeight - this.distanceBottom;
}
}
this.initDraggable();
});
}
this.isScrollHidden && window.addEventListener("scroll", this.handleScroll);
window.addEventListener("resize", this.handleResize);
},
beforeDestroy() {
if (this.id) {
window._DragBallComponent[this.id] = {
left: this.left,
top: this.top
};
}
window.removeEventListener("scroll", this.handleScroll);
window.removeEventListener("resize", this.handleResize);
},
computed: {
dragStyle() {
return {
left: this.left + 'px',
top: this.top + 'px',
zIndex: this.zIndex,
position: 'fixed',
}
},
floatDrag () {
return this.$refs.floatDrag
}
},
methods: {
/**
* 设置滚动监听(设置滚动时隐藏悬浮按钮,停止时显示)
*/
handleScroll() {
this.timer && clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.handleScrollEnd();
}, 200);
this.currentTop = document.documentElement.scrollTop || document.body.scrollTop;
if (this.left > this.clientWidth / 2) {
this.left = this.clientWidth + this.floatDrag.offsetWidth;
} else {
this.left = -this.floatDrag.offsetWidth;
}
},
/**
* 滚动结束
*/
handleScrollEnd() {
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
if (scrollTop === this.currentTop) {
if (this.left > this.clientWidth / 2) {
this.left = this.clientWidth - this.floatDrag.offsetWidth;
} else {
this.left = 0;
}
clearTimeout(this.timer);
}
},
/**
* 窗口resize监听
*/
handleResize() {
this.clientWidth = document.documentElement.clientWidth;
this.clientHeight = document.documentElement.clientHeight;
this.checkDraggablePosition();
},
/**
* 初始化draggable
*/
initDraggable() {
this.floatDrag.addEventListener("touchstart", this.toucheStart);
this.floatDrag.addEventListener("touchmove", this.touchMove);
this.floatDrag.addEventListener("touchend", this.touchEnd);
},
mouseDown(e) {
this.record = {
time: new Date().getTime(),
top: this.floatDrag.offsetTop,
left: this.floatDrag.offsetLeft,
x: e.clientX - this.floatDrag.offsetLeft,
y: e.clientY - this.floatDrag.offsetTop,
}
this.floatDrag.style.transition = "none";
this.canClick = false;
//
document.onmousemove = (e) => {
let left = e.clientX - this.record.x;
let top = e.clientY - this.record.y;
if (left < 0) {
left = 0
} else if (left > (window.innerWidth - this.floatDrag.offsetWidth)) {
left = window.innerWidth - this.floatDrag.offsetWidth
}
if (top < 0) {
top = 0
} else if (top > (window.innerHeight - this.floatDrag.offsetHeight)) {
top = window.innerHeight - this.floatDrag.offsetHeight
}
this.left = left;
this.top = top;
};
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
this.checkDraggablePosition();
this.floatDrag.style.transition = "all 0.3s";
// 点击事件
if ((Math.abs(this.record.top - this.floatDrag.offsetTop) < 5 && Math.abs(this.record.left - this.floatDrag.offsetLeft) < 5) || new Date().getTime() - this.record.time < 200) {
this.$emit("on-click")
}
}
},
toucheStart() {
this.canClick = false;
this.floatDrag.style.transition = "none";
},
touchMove(e) {
this.canClick = true;
if (e.targetTouches.length === 1) {
// 单指拖动
let touch = event.targetTouches[0];
let left = touch.clientX - this.floatDrag.offsetWidth / 2;
let top = touch.clientY - this.floatDrag.offsetHeight / 2;
if (left < 0) {
left = 0
} else if (left > (window.innerWidth - this.floatDrag.offsetWidth)) {
left = window.innerWidth - this.floatDrag.offsetWidth
}
if (top < 0) {
top = 0
} else if (top > (window.innerHeight - this.floatDrag.offsetHeight)) {
top = window.innerHeight - this.floatDrag.offsetHeight
}
this.left = left;
this.top = top;
}
},
touchEnd() {
if (!this.canClick) return;
this.floatDrag.style.transition = "all 0.3s";
this.checkDraggablePosition();
},
/**
* 判断元素显示位置在窗口改变和move end时调用
*/
checkDraggablePosition() {
if (this.left + this.floatDrag.offsetWidth / 2 >= this.clientWidth / 2) {
this.left = this.clientWidth - this.floatDrag.offsetWidth;
} else {
this.left = 0;
}
if (this.top < 0) {
this.top = 0;
}
if (this.top + this.floatDrag.offsetHeight >= this.clientHeight) {
this.top = this.clientHeight - this.floatDrag.offsetHeight;
}
}
},
};
</script>