ScreenElement.vue 4.1 KB

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