rhythmPracticeElement.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. <template>
  2. <div
  3. class="rhythmPracticeElement"
  4. :class="{ lock: elementInfo.lock }"
  5. :style="{
  6. top: elementInfo.top + 'px',
  7. left: elementInfo.left + 'px',
  8. width: elementInfo.width + 'px',
  9. height: elementInfo.height + 'px'
  10. }"
  11. >
  12. <div class="rotate-wrapper" :style="{ transform: `rotate(${elementInfo.rotate}deg)` }">
  13. <div
  14. class="element-content"
  15. v-contextmenu="contextmenus"
  16. @mousedown="$event => handleSelectElement($event)"
  17. @touchstart="$event => handleSelectElement($event)"
  18. >
  19. <div
  20. v-if="isShowMask"
  21. @mousedown.stop="$event => handleSelectElement($event, false)"
  22. @touchstart.stop="$event => handleSelectElement($event, false)"
  23. class="mask"
  24. ></div>
  25. <rhythmPracticePlayer :width="elementInfo.width" :height="elementInfo.height" :scale="canvasScale" :dataJson="elementInfo.dataJson" />
  26. <div
  27. :class="['handler-border', item]"
  28. v-for="item in ['t', 'b', 'l', 'r']"
  29. :key="item"
  30. @mousedown="$event => handleSelectElement($event)"
  31. @touchstart="$event => handleSelectElement($event)"
  32. ></div>
  33. </div>
  34. </div>
  35. </div>
  36. </template>
  37. <script setup lang="ts">
  38. import { storeToRefs } from "pinia"
  39. import { useMainStore } from "@/store"
  40. import type { PPTRhythmPracticeElement } from "@/types/slides"
  41. import type { ContextmenuItem } from "@/components/Contextmenu/types"
  42. import rhythmPracticePlayer from "./rhythmPracticePlayer"
  43. import { computed } from "vue"
  44. const props = defineProps<{
  45. elementInfo: PPTRhythmPracticeElement
  46. selectElement: (e: MouseEvent | TouchEvent, element: PPTRhythmPracticeElement, canMove?: boolean) => void
  47. contextmenus: () => ContextmenuItem[] | null
  48. }>()
  49. const mainStore = useMainStore()
  50. const { canvasScale } = storeToRefs(mainStore)
  51. /* 当没有选中 或者 拖动过程中加一个遮罩,以免事件进入 iframe 无法触发*/
  52. const isShowMask = computed(() => {
  53. return mainStore.handleElementId !== props.elementInfo.id || props.elementInfo.isMove
  54. })
  55. const handleSelectElement = (e: MouseEvent | TouchEvent, canMove = true) => {
  56. if (props.elementInfo.lock) return
  57. e.stopPropagation()
  58. props.selectElement(e, props.elementInfo, canMove)
  59. }
  60. </script>
  61. <style lang="scss" scoped>
  62. .rhythmPracticeElement {
  63. position: absolute;
  64. &.lock .handler-border {
  65. cursor: default;
  66. }
  67. }
  68. .rotate-wrapper {
  69. width: 100%;
  70. height: 100%;
  71. }
  72. .element-content {
  73. width: 100%;
  74. height: 100%;
  75. position: relative;
  76. .mask {
  77. position: absolute;
  78. width: 100%;
  79. height: 100%;
  80. }
  81. }
  82. .handler-border {
  83. position: absolute;
  84. cursor: move;
  85. &.t {
  86. width: 100%;
  87. height: 10px;
  88. top: 0;
  89. left: 0;
  90. }
  91. &.b {
  92. width: 100%;
  93. height: 10px;
  94. bottom: 0;
  95. left: 0;
  96. }
  97. &.l {
  98. width: 10px;
  99. height: 100%;
  100. left: 0;
  101. top: 0;
  102. }
  103. &.r {
  104. width: 10px;
  105. height: 100%;
  106. right: 0;
  107. top: 0;
  108. }
  109. }
  110. </style>