index.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <template>
  2. <div
  3. class="mouse-select-wrap"
  4. style="position: relative; user-select: none;"
  5. @mousedown="handleMouseDown"
  6. @mousemove="handleMouseMove"
  7. @mouseup="handleMouseUp"
  8. @mouseleave="handleMouseLeave"
  9. >
  10. <!-- 这里是需要进行框选的内容 -->
  11. <div :class="{ 'notSelect': isSelecting }">
  12. <slot />
  13. </div>
  14. <!-- 在鼠标框选移动时生成虚线框 -->
  15. <div
  16. v-if="isSelecting"
  17. :style="getSelectionBoxStyle"
  18. />
  19. </div>
  20. </template>
  21. <script>
  22. import { mapMutations, mapState } from 'vuex'
  23. let time = 0
  24. let newTime = 0
  25. export default {
  26. props: {
  27. offsetX: {
  28. type: Number,
  29. default: 340 + 50
  30. },
  31. offsetY: {
  32. type: Number,
  33. default: 73 + 50
  34. }
  35. },
  36. data () {
  37. return {
  38. isSelecting: false, // 是否正在进行框选
  39. isSelectDown: false, // 是否按下鼠标左键
  40. startX: 0, // 框选起始点的横坐标
  41. startY: 0, // 框选起始点的纵坐标
  42. endX: 0, // 框选结束点的横坐标
  43. endY: 0 // 框选结束点的纵坐标
  44. }
  45. },
  46. computed: {
  47. ...mapState('bigScreen', {
  48. shiftKeyDown: state => state.shiftKeyDown,
  49. scale: state => state.zoom / 100
  50. }),
  51. getSelectionBoxStyle () {
  52. // 计算虚线框的样式
  53. const left = Math.min(this.startX, this.endX) + 'px'
  54. const top = Math.min(this.startY, this.endY) + 'px'
  55. const width = Math.abs(this.endX - this.startX) + 'px'
  56. const height = Math.abs(this.endY - this.startY) + 'px'
  57. if (!this.isSelecting) {
  58. return {
  59. display: 'none'
  60. }
  61. }
  62. return {
  63. position: 'absolute',
  64. left,
  65. top,
  66. width,
  67. height,
  68. border: '1px dashed #007aff',
  69. background: '#2a2e3380'
  70. }
  71. }
  72. },
  73. methods: {
  74. ...mapMutations('bigScreen',
  75. [
  76. 'changeActiveCodes',
  77. 'changeActiveCode'
  78. ]
  79. ),
  80. handleMouseDown (event) {
  81. // 点击在底部背景上
  82. if (event.button === 0) {
  83. time = new Date()
  84. // 避免和shift + 点击多选组件冲突
  85. if (this.shiftKeyDown) {
  86. return
  87. }
  88. this.isSelectDown = true
  89. // 点击在底部背景上
  90. if (typeof event.target.className === 'string' && event.target.className.indexOf('mouse-select-wrap') !== -1) {
  91. this.startX = event.offsetX
  92. this.endX = event.offsetX
  93. this.startY = event.offsetY
  94. this.endY = event.offsetY
  95. } else if (typeof event.target.className === 'string' && event.target.className.indexOf('design-drag-wrap') !== -1) {
  96. this.startX = event.offsetX + 50
  97. this.endX = event.offsetX + 50
  98. this.startY = event.offsetY + 50
  99. this.endY = event.offsetY + 50
  100. } else if (event.target.className === '') {
  101. this.startX = event.offsetX + 50
  102. this.endX = event.offsetX + 50
  103. this.startY = event.offsetY + 50
  104. this.endY = event.offsetY + 50
  105. }
  106. }
  107. },
  108. handleMouseMove (event) {
  109. if (!this.isSelectDown) {
  110. return
  111. }
  112. newTime = new Date()
  113. // if (newTime - time > 300) {
  114. this.isSelecting = true
  115. // }
  116. if (this.isSelecting) {
  117. if (typeof event.target.className === 'string' && event.target.className.indexOf('mouse-select-wrap') !== -1) {
  118. this.endX = event.offsetX
  119. this.endY = event.offsetY
  120. } else if (typeof event.target.className === 'string' && (event.target.className.indexOf('design-drag-wrap') !== -1)) {
  121. this.endX = event.offsetX + 50
  122. this.endY = event.offsetY + 50
  123. }
  124. }
  125. },
  126. handleMouseUp (event) {
  127. this.isSelectDown = false
  128. // 按下鼠标和抬起鼠标时间间隔小表示单击,否则表示框选结束
  129. // 避免和shift + 点击多选组件冲突
  130. // 避免和右键点击冲突
  131. if (
  132. newTime - time < 300 &&
  133. !this.shiftKeyDown &&
  134. event.button !== 2
  135. ) {
  136. // 按下鼠标和抬起鼠标时间间隔小表示单击,否则表示框选结束
  137. // this.changeActiveCodes([])
  138. // this.changeActiveCode('')
  139. }
  140. // 鼠标按下,并开始选择
  141. if (event.button === 0 && this.isSelecting) {
  142. this.isSelecting = false
  143. if (newTime - time < 300) {
  144. // newTime = 0
  145. // time = 0
  146. // return
  147. }
  148. newTime = 0
  149. time = 0
  150. // 在这里可以根据起始点和结束点的坐标计算选中的区域,进行相应的操作
  151. this.$emit('selectArea', {
  152. startX: Math.min(this.startX, this.endX),
  153. startY: Math.min(this.startY, this.endY),
  154. endX: Math.max(this.startX, this.endX),
  155. endY: Math.max(this.startY, this.endY)
  156. })
  157. // 重置起始点和结束点的坐标
  158. this.startX = 0
  159. this.startY = 0
  160. this.endX = 0
  161. this.endY = 0
  162. } else if (!this.shiftKeyDown && !this.isSelecting) {
  163. // 重置起始点和结束点的坐标
  164. this.startX = 0
  165. this.startY = 0
  166. this.endX = 0
  167. this.endY = 0
  168. // this.$emit('selectArea', {
  169. // startX: Math.min(this.startX, this.endX),
  170. // startY: Math.min(this.startY, this.endY),
  171. // endX: Math.max(this.startX, this.endX),
  172. // endY: Math.max(this.startY, this.endY)
  173. // })
  174. // this.changeActiveCodes([])
  175. }
  176. },
  177. handleMouseLeave () {
  178. this.isSelecting = false
  179. this.isSelectDown = false
  180. this.startX = 0
  181. this.startY = 0
  182. this.endX = 0
  183. this.endY = 0
  184. }
  185. }
  186. }
  187. </script>
  188. <style scoped lang="scss">
  189. .mouse-select-wrap{
  190. width: 200%;
  191. height: 200%;
  192. margin: -50px;
  193. padding: 50px;
  194. }
  195. .notSelect {
  196. user-select: none;
  197. pointer-events: none;
  198. }
  199. </style>