mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
149 lines
4.9 KiB
Vue
149 lines
4.9 KiB
Vue
<template>
|
|
<div
|
|
class="screen-element"
|
|
:class="{ 'link': elementInfo.link }"
|
|
:id="`screen-element-${elementInfo.id}`"
|
|
:style="{
|
|
zIndex: elementIndex,
|
|
color: theme.fontColor,
|
|
fontFamily: theme.fontName,
|
|
visibility: needWaitAnimation ? 'hidden' : 'visible',
|
|
}"
|
|
:title="elementInfo.link?.target || ''"
|
|
@click="openLink()"
|
|
>
|
|
<component
|
|
:is="currentElementComponent"
|
|
:elementInfo="elementInfo"
|
|
></component>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { computed, defineComponent, PropType } from 'vue'
|
|
import { storeToRefs } from 'pinia'
|
|
import { useSlidesStore } from '@/store'
|
|
import { ElementTypes, PPTElement } from '@/types/slides'
|
|
|
|
import BaseImageElement from '@/views/components/element/ImageElement/BaseImageElement.vue'
|
|
import BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue'
|
|
import BaseShapeElement from '@/views/components/element/ShapeElement/BaseShapeElement.vue'
|
|
import BaseLineElement from '@/views/components/element/LineElement/BaseLineElement.vue'
|
|
import ScreenChartElement from '@/views/components/element/ChartElement/ScreenChartElement.vue'
|
|
import BaseTableElement from '@/views/components/element/TableElement/BaseTableElement.vue'
|
|
import BaseLatexElement from '@/views/components/element/LatexElement/BaseLatexElement.vue'
|
|
import ScreenVideoElement from '@/views/components/element/VideoElement/ScreenVideoElement.vue'
|
|
import ScreenAudioElement from '@/views/components/element/AudioElement/ScreenAudioElement.vue'
|
|
|
|
export default defineComponent({
|
|
name: 'screen-element',
|
|
props: {
|
|
elementInfo: {
|
|
type: Object as PropType<PPTElement>,
|
|
required: true,
|
|
},
|
|
elementIndex: {
|
|
type: Number,
|
|
required: true,
|
|
},
|
|
animationIndex: {
|
|
type: Number,
|
|
default: -1,
|
|
},
|
|
turnSlideToId: {
|
|
type: Function as PropType<(id: string) => void>,
|
|
required: true,
|
|
},
|
|
manualExitFullscreen: {
|
|
type: Function as PropType<() => void>,
|
|
required: true,
|
|
},
|
|
},
|
|
setup(props) {
|
|
const currentElementComponent = computed(() => {
|
|
const elementTypeMap = {
|
|
[ElementTypes.IMAGE]: BaseImageElement,
|
|
[ElementTypes.TEXT]: BaseTextElement,
|
|
[ElementTypes.SHAPE]: BaseShapeElement,
|
|
[ElementTypes.LINE]: BaseLineElement,
|
|
[ElementTypes.CHART]: ScreenChartElement,
|
|
[ElementTypes.TABLE]: BaseTableElement,
|
|
[ElementTypes.LATEX]: BaseLatexElement,
|
|
[ElementTypes.VIDEO]: ScreenVideoElement,
|
|
[ElementTypes.AUDIO]: ScreenAudioElement,
|
|
}
|
|
return elementTypeMap[props.elementInfo.type] || null
|
|
})
|
|
|
|
const { currentSlide, theme } = storeToRefs(useSlidesStore())
|
|
|
|
// 判断元素是否需要等待执行入场动画:等待执行的元素需要先隐藏
|
|
const needWaitAnimation = computed(() => {
|
|
const animations = currentSlide.value.animations || []
|
|
const elementIndexInAnimation = animations.findIndex(animation => animation.elId === props.elementInfo.id)
|
|
if (elementIndexInAnimation === -1) {
|
|
return false
|
|
}
|
|
|
|
// 首先判断是否 effect 为 in 的元素(多动画的第一条)
|
|
const firstAnimation = animations.find(animation => animation.elId === props.elementInfo.id)
|
|
if (!firstAnimation) {
|
|
return false
|
|
}
|
|
|
|
// 先判断 animationIndex 到哪步 判断动画最后一条如果不是
|
|
const findAnimationsList = animations.filter((animation, index) => index < props.animationIndex && animation.elId === props.elementInfo.id)
|
|
if (findAnimationsList.length) {
|
|
const lastAnimation = findAnimationsList[findAnimationsList.length - 1]
|
|
const effect = lastAnimation.effect || 'in' // VERSION 2022/5/7 兼容旧数据: effect 为空则为进场动画
|
|
if (effect === 'out') {
|
|
return false
|
|
}
|
|
|
|
if (elementIndexInAnimation >= props.animationIndex) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// 最后再判断effect
|
|
const firstEffectAnimation = animations.find(animation => animation.elId === props.elementInfo.id)
|
|
if (firstEffectAnimation) {
|
|
const effect = firstEffectAnimation.effect || 'in' // VERSION 2022/5/7 兼容旧数据: effect 为空则为进场动画
|
|
if (effect === 'out') {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
return true
|
|
})
|
|
|
|
// 打开元素绑定的超链接
|
|
const openLink = () => {
|
|
const link = props.elementInfo.link
|
|
if (!link) return
|
|
|
|
if (link.type === 'web') {
|
|
props.manualExitFullscreen()
|
|
window.open(link.target)
|
|
}
|
|
else if (link.type === 'slide') {
|
|
props.turnSlideToId(link.target)
|
|
}
|
|
}
|
|
|
|
return {
|
|
currentElementComponent,
|
|
needWaitAnimation,
|
|
theme,
|
|
openLink,
|
|
}
|
|
},
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.link {
|
|
cursor: pointer;
|
|
}
|
|
</style> |