/**
|
* @copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-draggable/index.ts
|
* 调整部分细节
|
*/
|
|
import { onBeforeUnmount, onMounted, reactive, ref, watchEffect } from 'vue';
|
import type { ComputedRef, Ref } from 'vue';
|
|
import { unrefElement } from '@vueuse/core';
|
|
export function useModalDraggable(
|
targetRef: Ref<HTMLElement | undefined>,
|
dragRef: Ref<HTMLElement | undefined>,
|
draggable: ComputedRef<boolean>,
|
) {
|
const transform = reactive({
|
offsetX: 0,
|
offsetY: 0,
|
});
|
|
const dragging = ref(false);
|
|
const onMousedown = (e: MouseEvent) => {
|
const downX = e.clientX;
|
const downY = e.clientY;
|
|
if (!targetRef.value) {
|
return;
|
}
|
|
const targetRect = targetRef.value.getBoundingClientRect();
|
|
const { offsetX, offsetY } = transform;
|
const targetLeft = targetRect.left;
|
const targetTop = targetRect.top;
|
const targetWidth = targetRect.width;
|
const targetHeight = targetRect.height;
|
const docElement = document.documentElement;
|
const clientWidth = docElement.clientWidth;
|
const clientHeight = docElement.clientHeight;
|
|
const minLeft = -targetLeft + offsetX;
|
const minTop = -targetTop + offsetY;
|
const maxLeft = clientWidth - targetLeft - targetWidth + offsetX;
|
const maxTop = clientHeight - targetTop - targetHeight + offsetY;
|
|
const onMousemove = (e: MouseEvent) => {
|
let moveX = offsetX + e.clientX - downX;
|
let moveY = offsetY + e.clientY - downY;
|
|
moveX = Math.min(Math.max(moveX, minLeft), maxLeft);
|
moveY = Math.min(Math.max(moveY, minTop), maxTop);
|
|
transform.offsetX = moveX;
|
transform.offsetY = moveY;
|
|
if (targetRef.value) {
|
targetRef.value.style.transform = `translate(${moveX}px, ${moveY}px)`;
|
dragging.value = true;
|
}
|
};
|
|
const onMouseup = () => {
|
dragging.value = false;
|
document.removeEventListener('mousemove', onMousemove);
|
document.removeEventListener('mouseup', onMouseup);
|
};
|
|
document.addEventListener('mousemove', onMousemove);
|
document.addEventListener('mouseup', onMouseup);
|
};
|
|
const onDraggable = () => {
|
const dragDom = unrefElement(dragRef);
|
if (dragDom && targetRef.value) {
|
dragDom.addEventListener('mousedown', onMousedown);
|
}
|
};
|
|
const offDraggable = () => {
|
const dragDom = unrefElement(dragRef);
|
if (dragDom && targetRef.value) {
|
dragDom.removeEventListener('mousedown', onMousedown);
|
}
|
};
|
|
const resetPosition = () => {
|
transform.offsetX = 0;
|
transform.offsetY = 0;
|
|
const target = unrefElement(targetRef);
|
if (target) {
|
target.style.transform = 'none';
|
}
|
};
|
|
onMounted(() => {
|
watchEffect(() => {
|
if (draggable.value) {
|
onDraggable();
|
} else {
|
offDraggable();
|
}
|
});
|
});
|
|
onBeforeUnmount(() => {
|
offDraggable();
|
});
|
|
return {
|
dragging,
|
resetPosition,
|
transform,
|
};
|
}
|