index.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. <!-- eslint-disable vue/no-unused-vars -->
  2. <!-- eslint-disable vue/valid-v-for -->
  3. <template>
  4. <div ref="wrapRef" class="svg-wrap" @mousemove="handleMouseMove">
  5. <svg
  6. version="1.1"
  7. baseProfile="full"
  8. xmlns="http://www.w3.org/2000/svg"
  9. xmlns:xlink="http://www.w3.org/1999/xlink"
  10. xmlns:ev="http://www.w3.org/2001/xml-events"
  11. :width="wrapSize.width"
  12. :height="wrapSize.height"
  13. >
  14. <SvgRect
  15. v-for="i in children"
  16. :key="i.id"
  17. v-bind="i"
  18. :draggingId="draggingId"
  19. :mousePos="curPos"
  20. @startLine="startLine"
  21. @startDrag="startDrag"
  22. @updatePos="updatePos"
  23. />
  24. <line v-if="lineStartPoint" v-bind="dashLineAttr"></line>
  25. </svg>
  26. </div>
  27. </template>
  28. <script setup>
  29. import { reactive, ref, onBeforeUnmount, onMounted, computed } from "vue";
  30. import SvgRect from "./components/svgRect.vue";
  31. import { findFromArray, getPosFromEvent } from "./utils/index";
  32. const wrapRef = ref(null);
  33. const childrenRefs = ref(null);
  34. let curPos = ref({ x: 0, y: 0 });
  35. const wrapSize = reactive({ width: 0, height: 0 });
  36. const draggingId = ref(0);
  37. const lineStartPoint = ref(null);
  38. const children = ref([
  39. { id: 1, pos: { x: 10, y: 10 }, size: { width: 100, height: 100 } },
  40. { id: 2, pos: { x: 20, y: 20 }, size: { width: 100, height: 100 } },
  41. { id: 3, pos: { x: 30, y: 30 }, size: { width: 100, height: 100 } },
  42. ]);
  43. const dashLineAttr = computed(() => {
  44. if (lineStartPoint.value) {
  45. return {
  46. x1: lineStartPoint.value?.cx,
  47. y1: lineStartPoint.value?.cy,
  48. x2: curPos.value.x,
  49. y2: curPos.value.y,
  50. stroke: "black",
  51. "stroke-dasharray": "3 4",
  52. "stroke-width": "2",
  53. };
  54. }
  55. return {};
  56. });
  57. function startDrag({ id, event }) {
  58. draggingId.value = id;
  59. lineStartPoint.value = null;
  60. curPos.value = getPosFromEvent(event);
  61. const { index, result } = findFromArray(children.value, (i) => i.id === id);
  62. children.value.splice(index, 1);
  63. children.value.push(result);
  64. }
  65. function startLine({ id, point }) {
  66. draggingId.value = 0;
  67. lineStartPoint.value = point;
  68. }
  69. function updatePos({ id, pos }) {
  70. const { result } = findFromArray(children.value, (i) => i.id === id);
  71. result.pos = pos;
  72. }
  73. function handleMouseMove(e) {
  74. curPos.value = getPosFromEvent(e);
  75. }
  76. function handleMouseUp() {
  77. draggingId.value = 0;
  78. lineStartPoint.value = null;
  79. }
  80. function initSvgSize() {
  81. // 避免因为转rem时有小数误差导致得滚动条
  82. wrapSize.width = wrapRef.value.offsetWidth - 1;
  83. wrapSize.height = wrapRef.value.offsetHeight - 1;
  84. }
  85. window.addEventListener("mouseup", handleMouseUp);
  86. window.addEventListener("resize", initSvgSize);
  87. onMounted(() => {
  88. initSvgSize();
  89. });
  90. onBeforeUnmount(() => {
  91. window.removeEventListener("mouseup", handleMouseUp);
  92. window.removeEventListener("resize", initSvgSize);
  93. });
  94. </script>
  95. <style lang="less" scoped>
  96. .svg-wrap {
  97. min-height: 400px;
  98. background-color: blue;
  99. background-image: linear-gradient(
  100. transparent 0px,
  101. transparent 2px,
  102. #fff 2px,
  103. #fff 15px
  104. ),
  105. linear-gradient(90deg, #ccc 0px, #ccc 2px, #fff 2px, #fff 15px);
  106. background-size: 15px 15px, 15px 15px;
  107. position: relative;
  108. svg {
  109. display: block;
  110. }
  111. }
  112. </style>