142 lines
4.4 KiB
Vue
142 lines
4.4 KiB
Vue
|
|
<template>
|
||
|
|
<div ref="" id="draggableElementView" class="draggable-box cursor-grab" :style="elementStyle"
|
||
|
|
@mousedown.passive="handleStart" @touchstart.passive="handleStart" @click="handleClick">
|
||
|
|
<slot></slot>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script lang="ts">
|
||
|
|
import { defineComponent, ref, onUnmounted } from 'vue';
|
||
|
|
import { addResizeTimeOut, removeResizeTimeOut } from '@/utils';
|
||
|
|
export default defineComponent({
|
||
|
|
name: 'PressDragComponent',
|
||
|
|
emits: ['click'],
|
||
|
|
props: {
|
||
|
|
storageKey: {
|
||
|
|
default: '',
|
||
|
|
},
|
||
|
|
},
|
||
|
|
setup(props, { emit }) {
|
||
|
|
const view = {
|
||
|
|
offsetWidth: 50,
|
||
|
|
offsetHeight: 50,
|
||
|
|
innerWidth: 750,
|
||
|
|
innerHeight: 1280,
|
||
|
|
};
|
||
|
|
const storageKeyVal = `_tem_drag_${props.storageKey}`;
|
||
|
|
|
||
|
|
const initil = () => {
|
||
|
|
const node = document.querySelector('#draggableElementView') as HTMLElement;
|
||
|
|
view.offsetWidth = node.offsetWidth;
|
||
|
|
view.offsetHeight = node.offsetHeight;
|
||
|
|
|
||
|
|
view.innerWidth =
|
||
|
|
window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||
|
|
view.innerHeight =
|
||
|
|
window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
|
||
|
|
};
|
||
|
|
addResizeTimeOut(initil);
|
||
|
|
const isDragging = ref(false);
|
||
|
|
const pressTimer = ref<number | null>(null);
|
||
|
|
const startTime = ref(0);
|
||
|
|
const elementStyle = ref<any>({
|
||
|
|
userSelect: 'none',
|
||
|
|
touchAction: 'none',
|
||
|
|
});
|
||
|
|
onMounted(() => {
|
||
|
|
nextTick(() => {
|
||
|
|
initil();
|
||
|
|
// if (props.storageKey && props.storageKey.length > 0) {
|
||
|
|
// let storageVal: any = localStorage.getItem(storageKeyVal);
|
||
|
|
// if (storageVal && storageVal.length > 0) {
|
||
|
|
// storageVal = storageVal.split(',');
|
||
|
|
// setStyle(storageVal[0], storageVal[1]);
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
});
|
||
|
|
});
|
||
|
|
const handleStart = (e: MouseEvent | TouchEvent) => {
|
||
|
|
e.preventDefault();
|
||
|
|
startTime.value = Date.now();
|
||
|
|
pressTimer.value = window.setTimeout(() => {
|
||
|
|
isDragging.value = true;
|
||
|
|
document.addEventListener('mousemove', handleDrag);
|
||
|
|
document.addEventListener('touchmove', handleDrag, { passive: false });
|
||
|
|
document.addEventListener('mouseup', handleEnd);
|
||
|
|
document.addEventListener('touchend', handleEnd);
|
||
|
|
}, 200);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleDrag = (e: MouseEvent | TouchEvent) => {
|
||
|
|
if (!isDragging.value) return;
|
||
|
|
e.preventDefault();
|
||
|
|
const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX;
|
||
|
|
const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY;
|
||
|
|
let left = clientX - view.offsetWidth / 2;
|
||
|
|
let top = clientY - view.offsetHeight / 2;
|
||
|
|
|
||
|
|
left = left > view.innerWidth - view.offsetWidth ? view.innerWidth - view.offsetWidth : left;
|
||
|
|
top = top > view.innerHeight - view.offsetHeight ? view.innerHeight - view.offsetHeight : top;
|
||
|
|
setStyle(left, top);
|
||
|
|
};
|
||
|
|
const setStyle = (left: number, top: number) => {
|
||
|
|
if (props.storageKey && props.storageKey.length > 0) {
|
||
|
|
localStorage.setItem(storageKeyVal, [left, top].join(','));
|
||
|
|
}
|
||
|
|
|
||
|
|
// if (left > innerWidth - 90) {
|
||
|
|
// left = innerWidth - 90;
|
||
|
|
// } else if (left < 30) {
|
||
|
|
// left = 30;
|
||
|
|
// }
|
||
|
|
// if (top > innerHeight - 90) {
|
||
|
|
// top = innerHeight - 90;
|
||
|
|
// } else if (top < 30) {
|
||
|
|
// top = 30;
|
||
|
|
// }
|
||
|
|
|
||
|
|
left = (left / view.innerWidth) * 100;
|
||
|
|
left = left < 0 ? 0 : left;
|
||
|
|
|
||
|
|
top = (top / view.innerHeight) * 100;
|
||
|
|
top = top < 0 ? 0 : top;
|
||
|
|
elementStyle.value = {
|
||
|
|
...elementStyle.value,
|
||
|
|
left: `${left}%`,
|
||
|
|
top: `${top}%`,
|
||
|
|
};
|
||
|
|
};
|
||
|
|
const handleEnd = () => {
|
||
|
|
clearTimeout(pressTimer.value!);
|
||
|
|
document.removeEventListener('mousemove', handleDrag);
|
||
|
|
document.removeEventListener('touchmove', handleDrag);
|
||
|
|
document.removeEventListener('mouseup', handleEnd);
|
||
|
|
document.removeEventListener('touchend', handleEnd);
|
||
|
|
isDragging.value = false;
|
||
|
|
};
|
||
|
|
const handleClick = (e: MouseEvent) => {
|
||
|
|
if (Date.now() - startTime.value > 200) return;
|
||
|
|
emit('click', e);
|
||
|
|
};
|
||
|
|
|
||
|
|
onUnmounted(() => {
|
||
|
|
handleEnd();
|
||
|
|
|
||
|
|
removeResizeTimeOut(initil);
|
||
|
|
});
|
||
|
|
return { elementStyle, handleStart, handleClick };
|
||
|
|
},
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
/* .draggable-box {
|
||
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||
|
|
transition: transform 0.1s, box-shadow 0.3s;
|
||
|
|
} */
|
||
|
|
|
||
|
|
.draggable-box:active {
|
||
|
|
transform: scale(0.98);
|
||
|
|
}
|
||
|
|
</style>
|