| | |
| | | <script setup> |
| | | import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue' |
| | | import videojs from 'video.js' |
| | | |
| | | const props = defineProps({ |
| | | width: { |
| | | type: String, |
| | | default: '800' |
| | | default: '800', |
| | | }, |
| | | modelValue: { |
| | | type: Boolean, |
| | | default: false |
| | | default: false, |
| | | }, |
| | | playUrl: { |
| | | type: String, |
| | | default: '' |
| | | default: '', |
| | | }, |
| | | title:{ |
| | | title: { |
| | | type: String, |
| | | default: '视频播放' |
| | | } |
| | | default: '视频播放', |
| | | }, |
| | | }) |
| | | |
| | | const emit = defineEmits(['update:modelValue']) |
| | | const handleClose = () => { |
| | | emit('update:modelValue', false) |
| | | const videoRefs = ref(null) |
| | | let player = null |
| | | |
| | | const dialogVisible = computed({ |
| | | get: () => props.modelValue, |
| | | set: value => emit('update:modelValue', value), |
| | | }) |
| | | |
| | | function getVideoType(url) { |
| | | const path = (url || '').split('?')[0].toLowerCase() |
| | | if (path.endsWith('.m3u8')) return 'application/x-mpegURL' |
| | | if (path.endsWith('.mp4')) return 'video/mp4' |
| | | if (path.endsWith('.webm')) return 'video/webm' |
| | | if (path.endsWith('.ogg') || path.endsWith('.ogv')) return 'video/ogg' |
| | | if (path.endsWith('.mov')) return 'video/quicktime' |
| | | return '' |
| | | } |
| | | |
| | | function destroyPlayer() { |
| | | if (!player) return |
| | | player.dispose() |
| | | player = null |
| | | } |
| | | |
| | | function getSource() { |
| | | const type = getVideoType(props.playUrl) |
| | | return { |
| | | src: props.playUrl, |
| | | ...(type ? { type } : {}), |
| | | } |
| | | } |
| | | |
| | | async function initPlayer() { |
| | | if (!props.modelValue || !props.playUrl) return |
| | | await nextTick() |
| | | if (!videoRefs.value) return |
| | | |
| | | if (player) { |
| | | player.src(getSource()) |
| | | player.load() |
| | | return |
| | | } |
| | | |
| | | player = videojs(videoRefs.value, { |
| | | controls: true, |
| | | preload: 'auto', |
| | | autoplay: false, |
| | | fluid: false, |
| | | width: '100%', |
| | | height: '600px', |
| | | sources: [getSource()], |
| | | }) |
| | | player.on('error', () => { |
| | | console.error('视频播放失败:', player?.error(), props.playUrl) |
| | | }) |
| | | } |
| | | |
| | | watch( |
| | | () => props.playUrl, |
| | | () => { |
| | | if (!props.modelValue || !props.playUrl) return |
| | | initPlayer() |
| | | } |
| | | ) |
| | | |
| | | onBeforeUnmount(destroyPlayer) |
| | | </script> |
| | | |
| | | <template> |
| | | <el-dialog |
| | | class="gd-dialog" |
| | | class="gd-dialog video-dialog" |
| | | :title="props.title" |
| | | append-to-body |
| | | v-model="props.modelValue" |
| | | v-model="dialogVisible" |
| | | width="60%" |
| | | destroy-on-close |
| | | :close-on-click-modal="false" |
| | | @close="handleClose" |
| | | @opened="initPlayer" |
| | | @closed="destroyPlayer" |
| | | > |
| | | <video ref="videoRefs" controls preload="auto" :src="props.playUrl"> |
| | | <source :src="props.playUrl" type="video/mp4" /> |
| | | </video> |
| | | <!-- <el-carousel trigger="click" :autoplay="false" @change="handleCarouselChange">--> |
| | | <!-- <el-carousel-item v-for="(item, index) in videoList" :key="index">--> |
| | | <!-- <video ref="videoRefs" controls preload="auto" :src="currentVideoUrl" @play="handleVideoPlay" @ended="handleVideoEnded(index)">--> |
| | | <!-- <source :src="item.smallUrl" type="video/mp4" />--> |
| | | <!-- </video>--> |
| | | <!-- </el-carousel-item>--> |
| | | <!-- </el-carousel>--> |
| | | <video |
| | | ref="videoRefs" |
| | | id="videoPlayDialogPlayer" |
| | | class="video-js vjs-default-skin vjs-big-play-centered" |
| | | controls |
| | | preload="auto" |
| | | playsinline |
| | | ></video> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <style lang="scss"> |
| | | .video-dialog { |
| | | .video-js { |
| | | height: 600px; |
| | | width: 100%; |
| | | } |
| | | } |
| | | </style> |
| | | |
| | | <style scoped lang="scss"> |
| | | video { |
| | | height: 600px; |
| | | :deep(.video-js .vjs-tech) { |
| | | height: 100%; |
| | | width: 100%; |
| | | } |
| | | </style> |