2
0

QmDialog.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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 lang="ts">
  41. // 不能用 <script setup lang="ts"> ,因为被上层用ref了,暂时没有解决方案
  42. import { defineComponent, onMounted, onUpdated, reactive, ref } from "vue";
  43. import { CloseOutlined } from "@ant-design/icons-vue";
  44. import { store } from "@/features/mark/store";
  45. export default defineComponent({
  46. name: "QmDialog",
  47. components: { CloseOutlined },
  48. props: {
  49. title: { type: String, default: "" },
  50. top: { type: String, default: "10%" },
  51. width: { type: String, default: "30%" },
  52. height: { type: String, default: "30%" },
  53. zIndex: { type: Number, default: 1020 },
  54. },
  55. emits: ["close"],
  56. setup({ top, width, height, title, zIndex }) {
  57. const positionStyle = reactive({
  58. top,
  59. left: "10%",
  60. width,
  61. height,
  62. zIndex,
  63. });
  64. const savedStyle = JSON.parse(
  65. sessionStorage.getItem("dialog-" + title) ?? "{}"
  66. );
  67. if (savedStyle?.top) positionStyle.top = savedStyle?.top;
  68. if (savedStyle?.left) positionStyle.left = savedStyle?.left;
  69. if (savedStyle?.width) positionStyle.width = savedStyle?.width;
  70. if (savedStyle?.height) positionStyle.height = savedStyle?.height;
  71. const mouseHandler = ref(null as unknown as HTMLHeadElement);
  72. const resizeHandler = ref(null as unknown as HTMLDivElement);
  73. const mousePosition = {
  74. offsetX: 0,
  75. offsetY: 0,
  76. };
  77. const handleDragMouseDown = (e: MouseEvent) => {
  78. document.addEventListener("mousemove", handleDragMouseMove);
  79. document.addEventListener("mouseup", handleDragMouseUp);
  80. // console.log(e);
  81. const { clientX, clientY } = e;
  82. mousePosition.offsetX = clientX;
  83. mousePosition.offsetY = clientY;
  84. };
  85. const handleDragMouseMove = (e: MouseEvent) => {
  86. const { clientX, clientY } = e;
  87. const windowWidth = window.innerWidth;
  88. const windowHeight = window.innerHeight;
  89. const newXRatio =
  90. parseFloat(positionStyle.left) / 100 +
  91. (clientX - mousePosition.offsetX) / windowWidth;
  92. const newYRatio =
  93. parseFloat(positionStyle.top) / 100 +
  94. (clientY - mousePosition.offsetY) / windowHeight;
  95. // console.log({
  96. // offsetX: mousePosition.offsetX,
  97. // offsetY: mousePosition.offsetY,
  98. // newYRatio,
  99. // newXRatio,
  100. // });
  101. if (newYRatio > 0 && newYRatio < 0.95) {
  102. positionStyle.top = newYRatio * 100 + "%";
  103. }
  104. if (newXRatio > 0 && newXRatio < 0.95) {
  105. positionStyle.left = newXRatio * 100 + "%";
  106. }
  107. mousePosition.offsetX = clientX;
  108. mousePosition.offsetY = clientY;
  109. };
  110. const handleDragMouseUp = (e: MouseEvent) => {
  111. mousePosition.offsetX = 0;
  112. mousePosition.offsetY = 0;
  113. mouseHandler.value.removeEventListener("mousedown", handleDragMouseDown);
  114. document.removeEventListener("mousemove", handleDragMouseMove);
  115. document.removeEventListener("mouseup", handleDragMouseUp);
  116. };
  117. const handleResizeMouseDown = (e: MouseEvent) => {
  118. document.addEventListener("mousemove", handleResizeMouseMove);
  119. document.addEventListener("mouseup", handleResizeMouseUp);
  120. const { clientX, clientY } = e;
  121. mousePosition.offsetX = clientX;
  122. mousePosition.offsetY = clientY;
  123. };
  124. const handleResizeMouseMove = (e: MouseEvent) => {
  125. // console.log(e);
  126. // console.log("mouse move");
  127. const { clientX, clientY } = e;
  128. // @ts-ignore
  129. const newXRatio = clientX - mousePosition.offsetX;
  130. const newYRatio = clientY - mousePosition.offsetY;
  131. positionStyle.width = parseFloat(positionStyle.width) + newXRatio + "px";
  132. positionStyle.height =
  133. parseFloat(positionStyle.height) + newYRatio + "px";
  134. mousePosition.offsetX = clientX;
  135. mousePosition.offsetY = clientY;
  136. };
  137. const handleResizeMouseUp = (e: MouseEvent) => {
  138. mousePosition.offsetX = 0;
  139. mousePosition.offsetY = 0;
  140. resizeHandler.value.removeEventListener(
  141. "mousedown",
  142. handleResizeMouseDown
  143. );
  144. document.removeEventListener("mousemove", handleResizeMouseMove);
  145. document.removeEventListener("mouseup", handleResizeMouseUp);
  146. };
  147. onMounted(() => {
  148. increaseZIndex();
  149. });
  150. onUpdated(() => {
  151. if (title) {
  152. sessionStorage.setItem(
  153. "dialog-" + title,
  154. JSON.stringify(positionStyle)
  155. );
  156. }
  157. });
  158. const increaseZIndex = () => {
  159. positionStyle.zIndex = store.maxModalZIndex++;
  160. if (store.maxModalZIndex === 5000) {
  161. store.maxModalZIndex = 1020;
  162. }
  163. };
  164. return {
  165. positionStyle,
  166. mouseHandler,
  167. resizeHandler,
  168. handleDragMouseDown,
  169. handleResizeMouseDown,
  170. increaseZIndex,
  171. };
  172. },
  173. });
  174. </script>
  175. <style scoped>
  176. .dialog-container {
  177. z-index: 1020;
  178. position: absolute;
  179. min-width: 100px;
  180. background-color: var(--app-container-bg-color);
  181. border: 1px solid var(--app-main-bg-color);
  182. border-radius: 5px;
  183. box-shadow: 0px 4px 8px 0px rgba(25, 27, 55, 0.1);
  184. }
  185. header {
  186. color: var(--app-main-text-color);
  187. border-bottom: 1px solid var(--app-main-bg-color);
  188. }
  189. .resize-handler {
  190. position: absolute;
  191. bottom: -10px;
  192. right: -10px;
  193. width: 20px;
  194. height: 20px;
  195. cursor: nwse-resize;
  196. }
  197. </style>