EditableElement.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <template>
  2. <div
  3. class="editable-element"
  4. ref="elementRef"
  5. :id="'editable-element-' + elementInfo.id"
  6. :style="{ zIndex: elementIndex }"
  7. >
  8. <component
  9. :is="currentElementComponent"
  10. :elementInfo="elementInfo"
  11. :selectElement="selectElement"
  12. :contextmenus="contextmenus"
  13. ></component>
  14. </div>
  15. </template>
  16. <script lang="ts">
  17. import { computed, defineComponent, PropType } from 'vue'
  18. import { PPTElement } from '@/types/slides'
  19. import { ContextmenuItem } from '@/components/Contextmenu/types'
  20. import useLockElement from '@/hooks/useLockElement'
  21. import useDeleteElement from '@/hooks/useDeleteElement'
  22. import useCombineElement from '@/hooks/useCombineElement'
  23. import useOrderElement from '@/hooks/useOrderElement'
  24. import useAlignElementToCanvas from '@/hooks/useAlignElementToCanvas'
  25. import useCopyAndPasteElement from '@/hooks/useCopyAndPasteElement'
  26. import { ElementOrderCommands, ElementAlignCommands } from '@/types/edit'
  27. import ImageElement from '@/views/components/element/ImageElement/index.vue'
  28. import TextElement from '@/views/components/element/TextElement/index.vue'
  29. import ShapeElement from '@/views/components/element/ShapeElement/index.vue'
  30. import LineElement from '@/views/components/element/LineElement/index.vue'
  31. export default defineComponent({
  32. name: 'editable-element',
  33. props: {
  34. elementInfo: {
  35. type: Object as PropType<PPTElement>,
  36. required: true,
  37. },
  38. elementIndex: {
  39. type: Number,
  40. required: true,
  41. },
  42. isMultiSelect: {
  43. type: Boolean,
  44. required: true,
  45. },
  46. selectElement: {
  47. type: Function as PropType<(e: MouseEvent, element: PPTElement, canMove?: boolean) => void>,
  48. required: true,
  49. },
  50. },
  51. setup(props) {
  52. const currentElementComponent = computed(() => {
  53. const elementTypeMap = {
  54. 'image': ImageElement,
  55. 'text': TextElement,
  56. 'shape': ShapeElement,
  57. 'line': LineElement,
  58. }
  59. return elementTypeMap[props.elementInfo.type] || null
  60. })
  61. const { orderElement } = useOrderElement()
  62. const { alignElementToCanvas } = useAlignElementToCanvas()
  63. const { combineElements, uncombineElements } = useCombineElement()
  64. const { deleteElement } = useDeleteElement()
  65. const { lockElement, unlockElement } = useLockElement()
  66. const { copyElement, cutElement } = useCopyAndPasteElement()
  67. const contextmenus = (): ContextmenuItem[] => {
  68. if(props.elementInfo.lock) {
  69. return [{
  70. text: '解锁',
  71. handler: () => unlockElement(props.elementInfo),
  72. }]
  73. }
  74. return [
  75. {
  76. text: '剪切',
  77. subText: 'Ctrl + X',
  78. handler: cutElement,
  79. },
  80. {
  81. text: '复制',
  82. subText: 'Ctrl + C',
  83. handler: copyElement,
  84. },
  85. { divider: true },
  86. {
  87. text: '层级排序',
  88. disable: props.isMultiSelect && !props.elementInfo.groupId,
  89. children: [
  90. { text: '置顶层', handler: () => orderElement(props.elementInfo, ElementOrderCommands.TOP) },
  91. { text: '置底层', handler: () => orderElement(props.elementInfo, ElementOrderCommands.BOTTOM) },
  92. { divider: true },
  93. { text: '上移一层', handler: () => orderElement(props.elementInfo, ElementOrderCommands.UP) },
  94. { text: '下移一层', handler: () => orderElement(props.elementInfo, ElementOrderCommands.DOWN) },
  95. ],
  96. },
  97. {
  98. text: '水平对齐',
  99. children: [
  100. { text: '水平居中', handler: () => alignElementToCanvas(ElementAlignCommands.HORIZONTAL) },
  101. { text: '左对齐', handler: () => alignElementToCanvas(ElementAlignCommands.LEFT) },
  102. { text: '右对齐', handler: () => alignElementToCanvas(ElementAlignCommands.RIGHT) },
  103. ],
  104. },
  105. {
  106. text: '垂直对齐',
  107. children: [
  108. { text: '垂直居中', handler: () => alignElementToCanvas(ElementAlignCommands.VERTICAL) },
  109. { text: '上对齐', handler: () => alignElementToCanvas(ElementAlignCommands.TOP) },
  110. { text: '下对齐', handler: () => alignElementToCanvas(ElementAlignCommands.BOTTOM) },
  111. ],
  112. },
  113. { divider: true },
  114. {
  115. text: props.elementInfo.groupId ? '取消组合' : '组合',
  116. subText: 'Ctrl + G',
  117. handler: props.elementInfo.groupId ? uncombineElements : combineElements,
  118. hide: !props.isMultiSelect,
  119. },
  120. {
  121. text: '锁定',
  122. subText: 'Ctrl + L',
  123. handler: lockElement,
  124. },
  125. {
  126. text: '删除',
  127. subText: 'Delete',
  128. handler: deleteElement,
  129. },
  130. ]
  131. }
  132. return {
  133. currentElementComponent,
  134. contextmenus,
  135. }
  136. },
  137. })
  138. </script>