On gists
08 Videoplayer (skeleton) Composition API
•
cdruc vue
VideoPlayer.vue
Raw
#
<script setup>
import axios from "axios";
import Player from "@vimeo/player";
import {throttle} from "lodash";
import ForwardIcon from "./svgs/ForwardIcon";
import BackwardIcon from "./svgs/BackwardIcon";
import LoadingIcon from "./svgs/LoadingIcon";
import {computed, onMounted, onUnmounted, ref, useSlots} from "vue";
const props = defineProps({
lessonId: Number,
trackProgress: Boolean
});
const speedIndex = ref(1);
let player = null;
const speedOptions = [0.75, 1, 1.25, 1.5, 1.75, 2.0];
const currentSpeed = computed(() => speedOptions[speedIndex.value]);
if (window.localStorage.getItem('speedIndex')) {
speedIndex.value = parseInt(window.localStorage.getItem('speedIndex'));
}
onMounted(() => {
player = new Player(useSlots().default()[0].el);
player.on('play', () => player.setPlaybackRate(currentSpeed.value));
if (props.trackProgress) {
player.on('progress', throttle((event) => updateProgress(event.percent), 10000));
player.on('ended', () => updateProgress(1));
}
});
onUnmounted(() => {
player.off('play');
player.off('progress');
player.off('ended');
});
function updateProgress(percent) {
return axios.put(`/lessons/${props.lessonId}/progress`, {percent: percent});
}
function toggleSpeed() {
if (typeof speedOptions[speedIndex.value + 1] !== "undefined") {
speedIndex.value += 1;
} else {
speedIndex.value = 0;
}
window.localStorage.setItem('speedIndex', speedIndex.value);
player.setPlaybackRate(currentSpeed.value);
}
async function goForward(seconds) {
const currentTime = await player.getCurrentTime();
const totalDuration = await player.getDuration();
player.setCurrentTime(Math.min(totalDuration, (currentTime + seconds)));
}
async function goBack(seconds) {
const currentTime = await player.getCurrentTime();
player.setCurrentTime(Math.max(0, (currentTime - seconds)));
}
</script>
<template>
<div class="relative aspect-w-16 aspect-h-9">
<div class="flex absolute inset-0 justify-center items-center">
<LoadingIcon class="w-14 h-14 text-white animate-spin"></LoadingIcon>
</div>
<slot></slot>
</div>
<div class="flex justify-end">
<div class="grid grid-cols-5 w-full max-w-xl divide-x divide-gray-700">
<button
class="inline-flex justify-center items-center p-2 space-x-1 text-base font-medium text-white cursor-pointer hover:text-orange-600 focus:outline-none"
@click="toggleSpeed()">
<span class="hidden sm:inline-block">Speed:</span><span>{{ currentSpeed }}x</span>
</button>
<button
class="inline-flex justify-center items-center p-2 space-x-1 text-base font-medium text-white cursor-pointer hover:text-orange-600 focus:outline-none"
@click="goBack(5)">
<BackwardIcon class="w-4 h-4"/>
<span>5s</span>
</button>
<button
class="inline-flex justify-center items-center p-2 space-x-1 text-base font-medium text-white cursor-pointer hover:text-orange-600 focus:outline-none"
@click="goForward(5)">
<span>5s</span>
<ForwardIcon class="w-4 h-4"/>
</button>
<button
class="inline-flex justify-center items-center p-2 space-x-1 text-base font-medium text-white cursor-pointer hover:text-orange-600 focus:outline-none"
@click="goBack(10)">
<BackwardIcon class="w-4 h-4"/>
<span>10s</span>
</button>
<button
class="inline-flex justify-center items-center p-2 space-x-1 text-base font-medium text-white cursor-pointer hover:text-orange-600 focus:outline-none"
@click="goForward(10)">
<span>10s</span>
<ForwardIcon class="w-4 h-4"/>
</button>
</div>
</div>
</template>