返回 slidev
SlidevVideo.vue
根目录 / packages / client / builtin / SlidevVideo.vue
1 <script setup lang="ts">
2 import { and } from '@vueuse/math'
3 import { computed, onMounted, ref, watch } from 'vue'
4 import { useNav } from '../composables/useNav'
5 import { useSlideContext } from '../context'
6 import { resolvedClickMap } from '../modules/v-click'
7
8 const props = defineProps<{
9 autoplay?: boolean | 'once'
10 autoreset?: 'slide' | 'click'
11 poster?: string
12 printPoster?: string
13 timestamp?: string | number
14 printTimestamp?: string | number | 'last'
15 controls?: boolean
16 }>()
17
18 const printPoster = computed(() => props.printPoster ?? props.poster)
19 const printTimestamp = computed(() => props.printTimestamp ?? props.timestamp ?? 0)
20
21 const { $slidev, $renderContext, $route } = useSlideContext()
22 const { isPrintMode } = useNav()
23
24 const noPlay = computed(() => isPrintMode.value || !['slide', 'presenter'].includes($renderContext.value))
25
26 const video = ref<HTMLMediaElement>()
27 const played = ref(false)
28
29 onMounted(() => {
30 if (noPlay.value)
31 return
32
33 const timestamp = +(props.timestamp ?? 0)
34 video.value!.currentTime = timestamp
35
36 const matchRoute = computed(() => !!$route && $route.no === $slidev?.nav.currentSlideNo)
37 const matchClick = computed(() => !!video.value && (resolvedClickMap.get(video.value)?.isShown?.value ?? true))
38 const matchRouteAndClick = and(matchRoute, matchClick)
39
40 watch(matchRouteAndClick, () => {
41 if (matchRouteAndClick.value) {
42 if (props.autoplay === true || (props.autoplay === 'once' && !played.value))
43 video.value!.play()
44 }
45 else {
46 video.value!.pause()
47 if (props.autoreset === 'click' || (props.autoreset === 'slide' && !matchRoute.value))
48 video.value!.currentTime = timestamp
49 }
50 }, { immediate: true })
51 })
52
53 function onLoadedMetadata(ev: Event) {
54 // The video may be loaded before component mounted
55 const element = ev.target as HTMLMediaElement
56 if (noPlay.value && (!printPoster.value || props.printTimestamp)) {
57 element.currentTime = printTimestamp.value === 'last'
58 ? element.duration
59 : +printTimestamp.value
60 }
61 }
62 </script>
63
64 <template>
65 <video
66 ref="video"
67 :poster="noPlay ? printPoster : props.poster"
68 :controls="!noPlay && props.controls"
69 @play="played = true"
70 @loadedmetadata="onLoadedMetadata"
71 >
72 <slot />
73 </video>
74 </template>
75
75 lines Plain Text