ScreenElement.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <template>
  2. <div
  3. class="screen-element"
  4. :class="{ 'link': elementInfo.link }"
  5. :id="`screen-element-${elementInfo.id}`"
  6. :style="{
  7. zIndex: elementIndex,
  8. color: theme.fontColor,
  9. fontFamily: theme.fontName,
  10. visibility: needWaitAnimation ? 'hidden' : 'visible',
  11. }"
  12. :title="elementInfo.link?.target || ''"
  13. @click="$event => openLink($event)"
  14. >
  15. <component
  16. :is="currentElementComponent"
  17. :elementInfo="elementInfo"
  18. ></component>
  19. </div>
  20. </template>
  21. <script lang="ts" setup>
  22. import { computed } from 'vue'
  23. import { storeToRefs } from 'pinia'
  24. import { useSlidesStore } from '@/store'
  25. import { ElementTypes, type PPTElement } from '@/types/slides'
  26. import BaseImageElement from '@/views/components/element/ImageElement/BaseImageElement.vue'
  27. import BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue'
  28. import BaseShapeElement from '@/views/components/element/ShapeElement/BaseShapeElement.vue'
  29. import BaseLineElement from '@/views/components/element/LineElement/BaseLineElement.vue'
  30. import BaseChartElement from '@/views/components/element/ChartElement/BaseChartElement.vue'
  31. import BaseTableElement from '@/views/components/element/TableElement/BaseTableElement.vue'
  32. import BaseLatexElement from '@/views/components/element/LatexElement/BaseLatexElement.vue'
  33. import ScreenVideoElement from '@/views/components/element/VideoElement/ScreenVideoElement.vue'
  34. import ScreenAudioElement from '@/views/components/element/AudioElement/ScreenAudioElement.vue'
  35. import BaseFrameElement from '@/views/components/element/FrameElement/BaseFrameElement.vue'
  36. const props = defineProps<{
  37. elementInfo: PPTElement
  38. elementIndex: number
  39. animationIndex: number
  40. turnSlideToId: (id: string) => void
  41. manualExitFullscreen: () => void
  42. }>()
  43. const currentElementComponent = computed<unknown>(() => {
  44. const elementTypeMap = {
  45. [ElementTypes.IMAGE]: BaseImageElement,
  46. [ElementTypes.TEXT]: BaseTextElement,
  47. [ElementTypes.SHAPE]: BaseShapeElement,
  48. [ElementTypes.LINE]: BaseLineElement,
  49. [ElementTypes.CHART]: BaseChartElement,
  50. [ElementTypes.TABLE]: BaseTableElement,
  51. [ElementTypes.LATEX]: BaseLatexElement,
  52. [ElementTypes.VIDEO]: ScreenVideoElement,
  53. [ElementTypes.AUDIO]: ScreenAudioElement,
  54. [ElementTypes.FRAME]: BaseFrameElement,
  55. }
  56. return elementTypeMap[props.elementInfo.type] || null
  57. })
  58. const { formatedAnimations, theme } = storeToRefs(useSlidesStore())
  59. // 判断元素是否需要等待执行入场动画:等待执行入场的元素需要先隐藏
  60. const needWaitAnimation = computed(() => {
  61. // 该元素在本页动画序列中的位置
  62. const elementIndexInAnimation = formatedAnimations.value.findIndex(item => {
  63. const elIds = item.animations.map(item => item.elId)
  64. return elIds.includes(props.elementInfo.id)
  65. })
  66. // 该元素未设置过动画
  67. if (elementIndexInAnimation === -1) return false
  68. // 若该元素已执行过动画,都无须隐藏
  69. // 具体来说:若已执行的最后一个动画为入场,显然无须隐藏;若已执行的最后一个动画为退场,由于保留了退场动画结束状态,也无需额外隐藏
  70. if (elementIndexInAnimation < props.animationIndex) return false
  71. // 若该元素未执行过动画,获取其将要执行的第一个动画
  72. // 若将要执行的第一个动画为入场,则需要隐藏,否则无须隐藏
  73. const firstAnimation = formatedAnimations.value[elementIndexInAnimation].animations.find(item => item.elId === props.elementInfo.id)
  74. if (firstAnimation?.type === 'in') return true
  75. return false
  76. })
  77. // 打开元素绑定的超链接
  78. const openLink = (e: MouseEvent) => {
  79. if ((e.target as HTMLElement).tagName === 'A') {
  80. props.manualExitFullscreen()
  81. return
  82. }
  83. const link = props.elementInfo.link
  84. if (!link) return
  85. if (link.type === 'web') {
  86. props.manualExitFullscreen()
  87. window.open(link.target)
  88. }
  89. else if (link.type === 'slide') {
  90. props.turnSlideToId(link.target)
  91. }
  92. }
  93. </script>
  94. <style lang="scss" scoped>
  95. .link {
  96. cursor: pointer;
  97. }
  98. </style>