QmDialog.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <template>
  2. <teleport to="body">
  3. <div
  4. class="dialog-container"
  5. :style="positionStyle"
  6. @click="increaseZIndex"
  7. >
  8. <header
  9. ref="mouseHandler"
  10. class="tw-flex tw-place-content-between tw-items-center"
  11. >
  12. <div
  13. class="
  14. tw-text-base
  15. tw-ml-5
  16. tw-my-2
  17. tw-cursor-move
  18. tw-flex-grow
  19. tw-font-bold
  20. "
  21. @mousedown="handleDragMouseDown"
  22. >
  23. {{ title }}
  24. </div>
  25. <a-button shape="circle" size="small" @click="$emit('close')">
  26. <template #icon><CloseOutlined /></template>
  27. </a-button>
  28. </header>
  29. <div class="tw-m-1 tw-overflow-auto" style="height: calc(100% - 50px)">
  30. <slot></slot>
  31. </div>
  32. <div
  33. ref="resizeHandler"
  34. class="resize-handler"
  35. @mousedown="handleResizeMouseDown"
  36. ></div>
  37. </div>
  38. </teleport>
  39. </template>
  40. <script setup lang="ts">
  41. import { onMounted, onUpdated, reactive } from "vue";
  42. import { CloseOutlined } from "@ant-design/icons-vue";
  43. import { store } from "@/store/store";
  44. const { top, width, height, title, zIndex } = withDefaults(
  45. defineProps<{
  46. title: string;
  47. top?: string;
  48. width?: string;
  49. height?: string;
  50. zIndex?: number;
  51. }>(),
  52. {
  53. title: "无标题",
  54. top: "10%",
  55. width: "30%",
  56. height: "30%",
  57. zIndex: 1020,
  58. }
  59. );
  60. defineEmits(["close"]);
  61. const positionStyle = reactive({
  62. top,
  63. left: "10%",
  64. width,
  65. height,
  66. zIndex,
  67. });
  68. const savedStyle = JSON.parse(
  69. sessionStorage.getItem("dialog-" + title) ?? "{}"
  70. );
  71. if (savedStyle?.top) positionStyle.top = savedStyle?.top;
  72. if (savedStyle?.left) positionStyle.left = savedStyle?.left;
  73. if (savedStyle?.width) positionStyle.width = savedStyle?.width;
  74. if (savedStyle?.height) positionStyle.height = savedStyle?.height;
  75. let mouseHandler = $ref(null as unknown as HTMLHeadElement);
  76. let resizeHandler = $ref(null as unknown as HTMLDivElement);
  77. const mousePosition = {
  78. offsetX: 0,
  79. offsetY: 0,
  80. };
  81. const handleDragMouseDown = (e: MouseEvent) => {
  82. document.addEventListener("mousemove", handleDragMouseMove);
  83. document.addEventListener("mouseup", handleDragMouseUp);
  84. // console.log(e);
  85. const { clientX, clientY } = e;
  86. mousePosition.offsetX = clientX;
  87. mousePosition.offsetY = clientY;
  88. };
  89. const handleDragMouseMove = (e: MouseEvent) => {
  90. const { clientX, clientY } = e;
  91. const windowWidth = window.innerWidth;
  92. const windowHeight = window.innerHeight;
  93. const newXRatio =
  94. parseFloat(positionStyle.left) / 100 +
  95. (clientX - mousePosition.offsetX) / windowWidth;
  96. const newYRatio =
  97. parseFloat(positionStyle.top) / 100 +
  98. (clientY - mousePosition.offsetY) / windowHeight;
  99. // console.log({
  100. // offsetX: mousePosition.offsetX,
  101. // offsetY: mousePosition.offsetY,
  102. // newYRatio,
  103. // newXRatio,
  104. // });
  105. if (newYRatio > 0 && newYRatio < 0.95) {
  106. positionStyle.top = newYRatio * 100 + "%";
  107. }
  108. if (newXRatio > 0 && newXRatio < 0.95) {
  109. positionStyle.left = newXRatio * 100 + "%";
  110. }
  111. mousePosition.offsetX = clientX;
  112. mousePosition.offsetY = clientY;
  113. };
  114. const handleDragMouseUp = (e: MouseEvent) => {
  115. mousePosition.offsetX = 0;
  116. mousePosition.offsetY = 0;
  117. mouseHandler.removeEventListener("mousedown", handleDragMouseDown);
  118. document.removeEventListener("mousemove", handleDragMouseMove);
  119. document.removeEventListener("mouseup", handleDragMouseUp);
  120. };
  121. const handleResizeMouseDown = (e: MouseEvent) => {
  122. document.addEventListener("mousemove", handleResizeMouseMove);
  123. document.addEventListener("mouseup", handleResizeMouseUp);
  124. const { clientX, clientY } = e;
  125. mousePosition.offsetX = clientX;
  126. mousePosition.offsetY = clientY;
  127. };
  128. const handleResizeMouseMove = (e: MouseEvent) => {
  129. // console.log(e);
  130. // console.log("mouse move");
  131. const { clientX, clientY } = e;
  132. // @ts-ignore
  133. const newXRatio = clientX - mousePosition.offsetX;
  134. const newYRatio = clientY - mousePosition.offsetY;
  135. positionStyle.width = parseFloat(positionStyle.width) + newXRatio + "px";
  136. positionStyle.height = parseFloat(positionStyle.height) + newYRatio + "px";
  137. mousePosition.offsetX = clientX;
  138. mousePosition.offsetY = clientY;
  139. };
  140. const handleResizeMouseUp = (e: MouseEvent) => {
  141. mousePosition.offsetX = 0;
  142. mousePosition.offsetY = 0;
  143. resizeHandler.removeEventListener("mousedown", handleResizeMouseDown);
  144. document.removeEventListener("mousemove", handleResizeMouseMove);
  145. document.removeEventListener("mouseup", handleResizeMouseUp);
  146. };
  147. onMounted(() => {
  148. increaseZIndex();
  149. });
  150. onUpdated(() => {
  151. if (title) {
  152. sessionStorage.setItem("dialog-" + title, JSON.stringify(positionStyle));
  153. }
  154. });
  155. const increaseZIndex = () => {
  156. positionStyle.zIndex = store.maxModalZIndex++;
  157. if (store.maxModalZIndex === 5000) {
  158. store.maxModalZIndex = 1020;
  159. }
  160. };
  161. </script>
  162. <style scoped>
  163. .dialog-container {
  164. z-index: 1020;
  165. position: absolute;
  166. min-width: 100px;
  167. background-color: var(--app-container-bg-color);
  168. border: 1px solid var(--app-main-bg-color);
  169. border-radius: 5px;
  170. box-shadow: 0px 4px 8px 0px rgba(25, 27, 55, 0.1);
  171. }
  172. header {
  173. color: var(--app-main-text-color);
  174. border-bottom: 1px solid var(--app-main-bg-color);
  175. }
  176. .resize-handler {
  177. position: absolute;
  178. bottom: -10px;
  179. right: -10px;
  180. width: 20px;
  181. height: 20px;
  182. cursor: nwse-resize;
  183. }
  184. </style>