index.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // 弹窗拖动
  2. import { ref, Ref, watch, nextTick, computed } from 'vue';
  3. type posType = {
  4. top: number;
  5. left: number;
  6. };
  7. /**
  8. * @params classList 可拖动地方的class值,也为唯一值
  9. * @params boxClass 容器class值必须为唯一值,这个class和useid拼接 作为缓存主键
  10. * @params dragShow 弹窗是否显示
  11. * @params userId 当前用户id
  12. */
  13. export default function useDrag(
  14. classList: string[],
  15. boxClass: string,
  16. dragShow: Ref<boolean>,
  17. userId: string
  18. ) {
  19. const pos = ref<posType>({
  20. top: -1, // -1 为初始值 代表没有缓存 默认居中
  21. left: -1
  22. });
  23. const useIdDargClass = userId + boxClass;
  24. watch(dragShow, () => {
  25. if (dragShow.value) {
  26. // 初始化pos值
  27. initPos();
  28. window.addEventListener('resize', refreshPos);
  29. nextTick(() => {
  30. const boxClassDom = document.querySelector(
  31. `.${boxClass}`
  32. ) as HTMLElement;
  33. if (!boxClassDom) {
  34. return;
  35. }
  36. classList.map((className: string) => {
  37. const classDom = document.querySelector(
  38. `.${className}`
  39. ) as HTMLElement;
  40. if (classDom) {
  41. classDom.style.cursor = 'move';
  42. drag(classDom, boxClassDom, pos);
  43. }
  44. });
  45. });
  46. } else {
  47. window.removeEventListener('resize', refreshPos);
  48. setCachePos(useIdDargClass, pos.value);
  49. }
  50. });
  51. const styleDrag = computed(() => {
  52. // 没有设置拖动的时候保持原本的
  53. return pos.value.left === -1 && pos.value.top === -1
  54. ? {}
  55. : {
  56. position: 'fixed',
  57. left: `${pos.value.left}px`,
  58. top: `${pos.value.top}px`
  59. };
  60. });
  61. function initPos() {
  62. const posCache = getCachePos(useIdDargClass);
  63. // 有缓存 用缓存的值,没有缓存用默认
  64. if (posCache) {
  65. pos.value = posCache;
  66. nextTick(() => {
  67. const _itme = setTimeout(() => {
  68. clearTimeout(_itme);
  69. refreshPos();
  70. }, 300);
  71. });
  72. }
  73. }
  74. function refreshPos() {
  75. if (pos.value.left === -1 && pos.value.top === -1) {
  76. return;
  77. }
  78. const boxClassDom = document.querySelector(`.${boxClass}`) as HTMLElement;
  79. if (!boxClassDom) return;
  80. const parentElementRect = boxClassDom.getBoundingClientRect();
  81. const clientWidth = document.documentElement.clientWidth;
  82. const clientHeight = document.documentElement.clientHeight;
  83. const { top, left } = pos.value;
  84. const maxLeft = clientWidth - parentElementRect.width;
  85. const maxTop = clientHeight - parentElementRect.height;
  86. let moveX = left;
  87. let moveY = top;
  88. const minLeft = 0;
  89. const minTop = 0;
  90. moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX;
  91. moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
  92. pos.value = {
  93. top: moveY,
  94. left: moveX
  95. };
  96. }
  97. return {
  98. pos,
  99. styleDrag
  100. };
  101. }
  102. // 拖动
  103. function drag(el: HTMLElement, parentElement: HTMLElement, pos: Ref<posType>) {
  104. function onDown(e: MouseEvent | TouchEvent) {
  105. const isTouchEv = isTouchEvent(e);
  106. const event = isTouchEv ? e.touches[0] : e;
  107. const parentElementRect = parentElement.getBoundingClientRect();
  108. const downX = event.clientX;
  109. const downY = event.clientY;
  110. const clientWidth = document.documentElement.clientWidth;
  111. const clientHeight = document.documentElement.clientHeight;
  112. const maxLeft = clientWidth - parentElementRect.width;
  113. const maxTop = clientHeight - parentElementRect.height;
  114. const minLeft = 0;
  115. const minTop = 0;
  116. function onMove(e: MouseEvent | TouchEvent) {
  117. const event = isTouchEvent(e) ? e.touches[0] : e;
  118. let moveX = parentElementRect.left + (event.clientX - downX);
  119. let moveY = parentElementRect.top + (event.clientY - downY);
  120. moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX;
  121. moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
  122. pos.value = {
  123. top: moveY,
  124. left: moveX
  125. };
  126. }
  127. function onUp() {
  128. document.removeEventListener(
  129. isTouchEv ? 'touchmove' : 'mousemove',
  130. onMove
  131. );
  132. document.removeEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
  133. }
  134. document.addEventListener(isTouchEv ? 'touchmove' : 'mousemove', onMove);
  135. document.addEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
  136. }
  137. el.addEventListener('mousedown', onDown);
  138. el.addEventListener('touchstart', onDown);
  139. }
  140. function isTouchEvent(e: MouseEvent | TouchEvent): e is TouchEvent {
  141. return window.TouchEvent && e instanceof window.TouchEvent;
  142. }
  143. // 缓存
  144. const localStorageName = 'dragCachePos';
  145. function getCachePos(useIdDargClass: string): null | undefined | posType {
  146. const localCachePos = localStorage.getItem(localStorageName);
  147. if (localCachePos) {
  148. try {
  149. return JSON.parse(localCachePos)[useIdDargClass];
  150. } catch {
  151. return null;
  152. }
  153. }
  154. return null;
  155. }
  156. function setCachePos(useIdDargClass: string, pos: posType) {
  157. const localCachePos = localStorage.getItem(localStorageName);
  158. let cachePosObj: Record<string, any> = {};
  159. if (localCachePos) {
  160. try {
  161. cachePosObj = JSON.parse(localCachePos);
  162. } catch {
  163. //
  164. }
  165. }
  166. cachePosObj[useIdDargClass] = pos;
  167. localStorage.setItem(localStorageName, JSON.stringify(cachePosObj));
  168. }