import { defineComponent, onMounted, onUnmounted, reactive, toRefs } from 'vue'; import { ref } from 'vue'; import TCPlayer from 'tcplayer.js'; import 'tcplayer.js/dist/tcplayer.min.css'; import styles from './index.module.less'; import iconplay from '@views/attend-class/image/icon-pause.png'; import iconpause from '@views/attend-class/image/icon-play.png'; import iconReplay from '@views/attend-class/image/icon-replay.png'; import iconPreviewDownload from '@views/attend-class/image/icon-preivew-download2.png'; import iconFullscreen from '@views/attend-class/image/icon-fullscreen.png'; import iconFullscreenExit from '@views/attend-class/image/icon-fullscreen-exit.png'; import iconSpeed from '@views/attend-class/image/icon-speed.png'; import { NSlider, useMessage } from 'naive-ui'; import { saveAs } from 'file-saver'; import { exitFullscreen } from '/src/utils'; export default defineComponent({ name: 'video-play', props: { src: { type: String, default: '' }, title: { type: String, default: '' }, poster: { type: String, default: '' }, isEmtry: { type: Boolean, default: false }, isDownload: { type: Boolean, default: false }, fullscreen: { type: Boolean, default: false } }, emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset'], setup(props, { emit, expose }) { const message = useMessage(); const videoId = 'vFullscreen' + Date.now() + Math.floor(Math.random() * 100); const { src, poster, isEmtry } = toRefs(props); const videoFroms = reactive({ isFullScreen: false, // 是否全屏 paused: true, currentTimeNum: 0, currentTime: '00:00', durationNum: 0, duration: '00:00', showBar: true, timer: null as any, speedControl: false, speedStyle: { left: '1px' }, defaultSpeed: 1 // 默认速度 }); const videoRef = ref(); const videoItem = ref(); const videoID = 'video' + Date.now() + Math.floor(Math.random() * 100); // 对时间进行格式化 const timeFormat = (num: number) => { if (num > 0) { const m = Math.floor(num / 60); const s = num % 60; return (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s); } else { return '00:00'; } }; // const toggleHideControl = (isShow = false) => { videoFroms.showBar = isShow; videoFroms.speedControl = false; }; const onReplay = () => { videoFroms.speedControl = false; if (!videoItem.value) return; videoItem.value.currentTime(0); }; // 切换音频播放 const onToggleVideo = (e?: MouseEvent) => { videoFroms.speedControl = false; e?.stopPropagation(); if (videoFroms.paused) { videoItem.value.play(); videoFroms.paused = false; } else { videoItem.value.pause(); videoFroms.paused = true; } emit('togglePlay', videoFroms.paused); }; // 下载资源 const onDownload = () => { if (!props.src) { message.error('下载失败'); return; } const fileUrl = props.src; // 发起Fetch请求 fetch(fileUrl) .then(response => response.blob()) .then(blob => { saveAs(blob, props.title || new Date().getTime() + ''); }) .catch(() => { message.error('下载失败'); }); }; /** 延迟收起模态框 */ const setModelOpen = (status = true) => { clearTimeout(videoFroms.timer); toggleHideControl(status); videoFroms.timer = setTimeout(() => { toggleHideControl(false); }, 3000); }; const __init = () => { if (videoItem.value) { videoItem.value.poster(poster.value); // 封面 videoItem.value.src(isEmtry.value ? '' : src.value); // url 播放地址 // 初步加载时 videoItem.value.one('loadedmetadata', () => { console.log(' Loading metadata'); // 获取时长 videoFroms.duration = timeFormat( Math.round(videoItem.value.duration()) ); videoFroms.durationNum = videoItem.value.duration(); emit('loadedmetadata', videoItem.value); onToggleVideo(); }); // 视频播放时加载 videoItem.value.on('timeupdate', () => { videoFroms.currentTime = timeFormat( Math.round(videoItem.value?.currentTime() || 0) ); videoFroms.currentTimeNum = videoItem.value.currentTime(); }); // 视频播放结束 videoItem.value.on('ended', () => { videoFroms.paused = true; emit('ended'); }); videoItem.value.on('play', () => { setModelOpen(); }); videoItem.value.on('pause', () => { clearTimeout(videoFroms.timer); videoFroms.showBar = true; }); } }; /** 全屏 */ const isElementFullscreen = (element: any) => { const dom: any = document; return ( element === (dom.fullscreenElement || dom.webkitFullscreenElement || dom.mozFullScreenElement || dom.msFullscreenElement) ); }; const onFullScreen = () => { const el: any = document.querySelector('#' + videoId); // //进入全屏 if (el) { if (isElementFullscreen(el)) { exitFullscreen(); } else { (el.requestFullscreen && el.requestFullscreen()) || (el.mozRequestFullScreen && el.mozRequestFullScreen()) || (el.webkitRequestFullscreen && el.webkitRequestFullscreen()) || (el.msRequestFullscreen && el.msRequestFullscreen()); } // videoFroms.isFullScreen = isElementFullscreen(el); } }; const onFullScreenChange = () => { if (document.fullscreenElement) { videoFroms.isFullScreen = true; } else { videoFroms.isFullScreen = false; } }; onMounted(() => { videoItem.value = TCPlayer(videoID, { appID: '', controls: false, autoPlay: true }); // player-container-id 为播放器容器 ID,必须与 html 中一致 __init(); window.addEventListener('fullscreenchange', onFullScreenChange); }); onUnmounted(() => { window.removeEventListener('fullscreenchange', onFullScreenChange); if (videoItem.value) { videoItem.value.pause(); videoItem.value.dispose(); videoItem.value = null; } }); expose({ // changePlayBtn, toggleHideControl }); return () => (