use-modal-draggable.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /**
  2. * @copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-draggable/index.ts
  3. * 调整部分细节
  4. */
  5. import type { ComputedRef, Ref } from 'vue';
  6. import { onBeforeUnmount, onMounted, reactive, ref, watchEffect } from 'vue';
  7. import { unrefElement } from '@vueuse/core';
  8. export function useModalDraggable(
  9. targetRef: Ref<HTMLElement | undefined>,
  10. dragRef: Ref<HTMLElement | undefined>,
  11. draggable: ComputedRef<boolean>,
  12. ) {
  13. const transform = reactive({
  14. offsetX: 0,
  15. offsetY: 0,
  16. });
  17. const dragging = ref(false);
  18. const onMousedown = (e: MouseEvent) => {
  19. const downX = e.clientX;
  20. const downY = e.clientY;
  21. if (!targetRef.value) {
  22. return;
  23. }
  24. const targetRect = targetRef.value.getBoundingClientRect();
  25. const { offsetX, offsetY } = transform;
  26. const targetLeft = targetRect.left;
  27. const targetTop = targetRect.top;
  28. const targetWidth = targetRect.width;
  29. const targetHeight = targetRect.height;
  30. const docElement = document.documentElement;
  31. const clientWidth = docElement.clientWidth;
  32. const clientHeight = docElement.clientHeight;
  33. const minLeft = -targetLeft + offsetX;
  34. const minTop = -targetTop + offsetY;
  35. const maxLeft = clientWidth - targetLeft - targetWidth + offsetX;
  36. const maxTop = clientHeight - targetTop - targetHeight + offsetY;
  37. const onMousemove = (e: MouseEvent) => {
  38. let moveX = offsetX + e.clientX - downX;
  39. let moveY = offsetY + e.clientY - downY;
  40. moveX = Math.min(Math.max(moveX, minLeft), maxLeft);
  41. moveY = Math.min(Math.max(moveY, minTop), maxTop);
  42. transform.offsetX = moveX;
  43. transform.offsetY = moveY;
  44. if (targetRef.value) {
  45. targetRef.value.style.transform = `translate(${moveX}px, ${moveY}px)`;
  46. dragging.value = true;
  47. }
  48. };
  49. const onMouseup = () => {
  50. dragging.value = false;
  51. document.removeEventListener('mousemove', onMousemove);
  52. document.removeEventListener('mouseup', onMouseup);
  53. };
  54. document.addEventListener('mousemove', onMousemove);
  55. document.addEventListener('mouseup', onMouseup);
  56. };
  57. const onDraggable = () => {
  58. const dragDom = unrefElement(dragRef);
  59. if (dragDom && targetRef.value) {
  60. dragDom.addEventListener('mousedown', onMousedown);
  61. }
  62. };
  63. const offDraggable = () => {
  64. const dragDom = unrefElement(dragRef);
  65. if (dragDom && targetRef.value) {
  66. dragDom.removeEventListener('mousedown', onMousedown);
  67. }
  68. };
  69. const resetPosition = () => {
  70. transform.offsetX = 0;
  71. transform.offsetY = 0;
  72. const target = unrefElement(targetRef);
  73. if (target) {
  74. target.style.transform = 'none';
  75. }
  76. };
  77. onMounted(() => {
  78. watchEffect(() => {
  79. if (draggable.value) {
  80. onDraggable();
  81. } else {
  82. offDraggable();
  83. }
  84. });
  85. });
  86. onBeforeUnmount(() => {
  87. offDraggable();
  88. });
  89. return {
  90. dragging,
  91. resetPosition,
  92. transform,
  93. };
  94. }