134 lines
2.4 KiB
Vue
134 lines
2.4 KiB
Vue
|
|
<script setup lang="ts">
|
||
|
|
import { onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
|
||
|
|
|
||
|
|
import Player from 'xgplayer';
|
||
|
|
|
||
|
|
import 'xgplayer/dist/index.min.css';
|
||
|
|
|
||
|
|
interface Props {
|
||
|
|
src: string;
|
||
|
|
autoplay?: boolean;
|
||
|
|
controls?: boolean;
|
||
|
|
thumbnail?: boolean;
|
||
|
|
width?: number | string;
|
||
|
|
height?: number | string;
|
||
|
|
poster?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
const props = withDefaults(defineProps<Props>(), {
|
||
|
|
autoplay: false,
|
||
|
|
controls: true,
|
||
|
|
thumbnail: false,
|
||
|
|
width: '100%',
|
||
|
|
height: '100%',
|
||
|
|
poster: undefined,
|
||
|
|
});
|
||
|
|
|
||
|
|
const emit = defineEmits<{
|
||
|
|
ready: [player: Player];
|
||
|
|
error: [error: any];
|
||
|
|
ended: [];
|
||
|
|
}>();
|
||
|
|
|
||
|
|
const containerRef = ref<HTMLDivElement>();
|
||
|
|
const player = shallowRef<Player | null>(null);
|
||
|
|
|
||
|
|
function createPlayer() {
|
||
|
|
if (!containerRef.value || !props.src) return;
|
||
|
|
|
||
|
|
player.value?.destroy();
|
||
|
|
player.value = null;
|
||
|
|
|
||
|
|
const ignores = props.thumbnail
|
||
|
|
? [
|
||
|
|
'cssfullscreen',
|
||
|
|
'screenshot',
|
||
|
|
'pip',
|
||
|
|
'miniscreen',
|
||
|
|
'keyboard',
|
||
|
|
'download',
|
||
|
|
'playbackrate',
|
||
|
|
'time',
|
||
|
|
'definition',
|
||
|
|
'fullscreen',
|
||
|
|
'loading',
|
||
|
|
'mobile',
|
||
|
|
'pc',
|
||
|
|
'play',
|
||
|
|
'poster',
|
||
|
|
'progress',
|
||
|
|
'replay',
|
||
|
|
'start',
|
||
|
|
'volume',
|
||
|
|
]
|
||
|
|
: [];
|
||
|
|
|
||
|
|
const p = new Player({
|
||
|
|
el: containerRef.value,
|
||
|
|
url: props.src,
|
||
|
|
autoplay: props.autoplay,
|
||
|
|
controls: props.thumbnail ? false : props.controls,
|
||
|
|
closeVideoClick: props.thumbnail,
|
||
|
|
closeVideoDblclick: props.thumbnail,
|
||
|
|
ignores,
|
||
|
|
fluid: true,
|
||
|
|
fitVideoSize: 'fixWidth',
|
||
|
|
videoInit: true,
|
||
|
|
poster: props.poster,
|
||
|
|
playsinline: true,
|
||
|
|
enableContextmenu: !props.thumbnail,
|
||
|
|
});
|
||
|
|
|
||
|
|
p.on('ready', () => {
|
||
|
|
emit('ready', p);
|
||
|
|
});
|
||
|
|
|
||
|
|
p.on('error', (e: any) => {
|
||
|
|
emit('error', e);
|
||
|
|
});
|
||
|
|
|
||
|
|
p.on('ended', () => {
|
||
|
|
emit('ended');
|
||
|
|
});
|
||
|
|
|
||
|
|
player.value = p;
|
||
|
|
}
|
||
|
|
|
||
|
|
onMounted(() => {
|
||
|
|
createPlayer();
|
||
|
|
});
|
||
|
|
|
||
|
|
onBeforeUnmount(() => {
|
||
|
|
player.value?.destroy();
|
||
|
|
player.value = null;
|
||
|
|
});
|
||
|
|
|
||
|
|
watch(
|
||
|
|
() => props.src,
|
||
|
|
() => {
|
||
|
|
createPlayer();
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
defineExpose({
|
||
|
|
getPlayer: () => player.value,
|
||
|
|
play: () => player.value?.play(),
|
||
|
|
pause: () => player.value?.pause(),
|
||
|
|
destroy: () => {
|
||
|
|
player.value?.destroy();
|
||
|
|
player.value = null;
|
||
|
|
},
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<template>
|
||
|
|
<div ref="containerRef" class="xg-video-player"></div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.xg-video-player {
|
||
|
|
width: v-bind(width);
|
||
|
|
height: v-bind(height);
|
||
|
|
}
|
||
|
|
</style>
|