TelViewTem.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <template>
  2. <div class="tel-view-tem" @mousedown="onMouseDown">
  3. <img class="bg-src" :src="bgSrc" />
  4. <!-- 拖动选区样式 -->
  5. <div v-if="isDragging" class="drag-area" :style="dragAreaStyle"></div>
  6. <div class="pro-content">
  7. <slot></slot>
  8. </div>
  9. </div>
  10. </template>
  11. <script setup lang="ts">
  12. import { ref, computed, watch } from 'vue';
  13. import { propTypes } from '@/utils/propTypes';
  14. const props = defineProps({
  15. width: propTypes.number.def(750),
  16. minHeight: propTypes.number.def(1000),
  17. bgColor: propTypes.string.def('#fff'),
  18. enableDraw: propTypes.bool.def(true),
  19. bgSrc: propTypes.string.def(''),
  20. });
  21. const emit = defineEmits(['selectArea']);
  22. const isDragging = ref(false);
  23. const startPoint = ref({ x: 0, y: 0 });
  24. const endPoint = ref({ x: 0, y: 0 });
  25. const imgHeight = ref(props.minHeight);
  26. const imgWidth = ref(props.width);
  27. const containerStyle: any = computed(() => {
  28. if (props.bgSrc) {
  29. return {
  30. width: props.width ? `${props.width}px` : '100%',
  31. height: `${imgHeight.value}px`,
  32. backgroundImage: `url(${props.bgSrc})`,
  33. backgroundSize: 'contain',
  34. backgroundRepeat: 'no-repeat',
  35. backgroundPosition: 'center',
  36. position: 'relative',
  37. userSelect: 'none',
  38. minHeight: `${imgHeight.value}px`,
  39. backgroundColor: props.bgColor,
  40. };
  41. }
  42. return {
  43. width: `${props.width}px`,
  44. minHeight: `${props.minHeight}px`,
  45. background: props.bgColor,
  46. position: 'relative',
  47. userSelect: 'none',
  48. };
  49. });
  50. const dragAreaStyle: any = computed(() => {
  51. const x = Math.min(startPoint.value.x, endPoint.value.x);
  52. const y = Math.min(startPoint.value.y, endPoint.value.y);
  53. const w = Math.abs(endPoint.value.x - startPoint.value.x);
  54. const h = Math.abs(endPoint.value.y - startPoint.value.y);
  55. return {
  56. position: 'absolute',
  57. left: `${x}px`,
  58. top: `${y}px`,
  59. width: `${w}px`,
  60. height: `${h}px`,
  61. border: '2px dashed #409eff',
  62. background: 'rgba(116, 251, 229,0.3)',
  63. pointerEvents: 'none',
  64. zIndex: 10,
  65. };
  66. });
  67. function onMouseDown(e: MouseEvent) {
  68. if (!props.enableDraw) return;
  69. if (e.button !== 0) return;
  70. const rect = (e.target as HTMLElement).getBoundingClientRect();
  71. startPoint.value = {
  72. x: e.clientX - rect.left,
  73. y: e.clientY - rect.top,
  74. };
  75. endPoint.value = { ...startPoint.value };
  76. isDragging.value = true;
  77. window.addEventListener('mousemove', onMouseMove);
  78. window.addEventListener('mouseup', onMouseUp);
  79. }
  80. function onMouseMove(e: MouseEvent) {
  81. if (!isDragging.value) return;
  82. const rect = (e.target as HTMLElement).closest('.tel-view-tem')?.getBoundingClientRect();
  83. if (!rect) return;
  84. endPoint.value = {
  85. x: e.clientX - rect.left,
  86. y: e.clientY - rect.top,
  87. };
  88. }
  89. function onMouseUp() {
  90. if (!isDragging.value) return;
  91. isDragging.value = false;
  92. emit('selectArea', {
  93. start: { ...startPoint.value },
  94. end: { ...endPoint.value },
  95. rect: {
  96. x: Math.min(startPoint.value.x, endPoint.value.x),
  97. y: Math.min(startPoint.value.y, endPoint.value.y),
  98. w: Math.abs(endPoint.value.x - startPoint.value.x),
  99. h: Math.abs(endPoint.value.y - startPoint.value.y),
  100. },
  101. });
  102. window.removeEventListener('mousemove', onMouseMove);
  103. window.removeEventListener('mouseup', onMouseUp);
  104. }
  105. </script>
  106. <style scoped lang="scss">
  107. .tel-view-tem {
  108. box-sizing: border-box;
  109. overflow: hidden;
  110. position: relative;
  111. }
  112. .drag-area {
  113. position: relative;
  114. z-index: 100;
  115. transition: none;
  116. }
  117. .bg-src {
  118. width: 750px;
  119. display: block;
  120. user-select: none;
  121. pointer-events: none;
  122. height: auto;
  123. object-fit: contain;
  124. z-index: -1;
  125. }
  126. .pro-content {
  127. position: absolute;
  128. left: 0;
  129. top: 0;
  130. right: 0;
  131. bottom: 0;
  132. }
  133. </style>