import { defineComponent, nextTick, onMounted, reactive, toRefs, watch } from 'vue'; import { ref } from 'vue'; import styles from './index.module.less'; import iconLoop from '../../image/icon-loop.png'; import iconLoopActive from '../../image/icon-loop-active.png'; import iconplay from '../../image/icon-play.png'; import iconpause from '../../image/icon-pause.png'; import { NSlider } from 'naive-ui'; import Vudio from 'vudio.js'; import { getSecondRPM } from '@/helpers/utils'; import { Slider, showToast } from 'vant'; import tickMp3 from '../../image/tick.mp3'; export default defineComponent({ name: 'video-play', props: { item: { type: Object, default: () => { return {}; } }, show: { type: Boolean, default: false }, pageVisibility: { type: String, default: '' }, showModel: { type: Boolean, default: false }, isEmtry: { type: Boolean, default: false } }, emits: ['loadedmetadata', 'togglePlay', 'ended', 'reset', 'close'], setup(props, { emit }) { const { item, isEmtry } = toRefs(props); const data = reactive({ speedInKbps: '', timer: null as any, currentTime: 0, duration: 0.1, loop: false, dragStatus: false, // 是否开始拖动 playState: 'pause' as 'play' | 'pause', vudio: null as any, afterMa3: true, count: 0 }); const canvasRef: any = ref(); const audioRef: any = ref(); const contetRef = ref(); watch( () => props.show, val => { data.count = 0; if (val && props.item.autoPlay) { // data.count = 0; // audioRef.value.src = item.value.content; onToggleAudio(); } else { audioRef.value.pause(); // audioRef.value.src = ''; data.playState = 'pause'; // data.vudio = null; } } ); // watch( // () => props.item, // () => { // // data.count = 0; // // audioRef.value.src = item.value.content; // onToggleAudio(); // } // ); watch( () => props.pageVisibility, val => { if (val === 'hidden' && props.show) { audioRef.value.pause(); data.playState = 'pause'; } } ); // 切换音频播放 const onToggleAudio = () => { if (audioRef.value.paused) { audioRef.value.play(); data.playState = 'play'; // nextTick(() => { // onInit(audioRef.value, canvasRef.value); // setTimeout(() => { // onInit(audioRef.value, canvasRef.value); // }, 100); // console.log(data.vudio, 'data.vudio'); // if (data.vudio) { // data.vudio.dance(); // } }); } else { audioRef.value.pause(); data.playState = 'pause'; } }; const onInit = (audio: undefined, canvas: undefined) => { if (!data.vudio && data.count > 1) { console.log(data.vudio, 'data.vudio'); try { const rect = contetRef.value.getBoundingClientRect() || { width: 200, height: 200 }; data.vudio = new Vudio(audio, canvas, { effect: 'waveform', accuracy: 128, width: rect.width, height: rect.height, waveform: { maxHeight: 160, color: [ [0, '#44D1FF'], [0.5, '#44D1FF'], [0.5, '#198CFE'], [1, '#198CFE'] ], prettify: false } }); data.vudio.dance(); } catch (e) { console.log(e, 'e'); } } else { } }; /** 加载成功 */ const onLoadedmetadata = () => { data.duration = audioRef.value?.duration; // onInit(audioRef.value, canvasRef.value); if (props.item.autoPlay && audioRef.value && props.show) { // data.vudio = null; // data.count = 0; onToggleAudio(); } // if (audioRef.value) { // audioRef.value.stop = () => { // audioRef.value?.pause(); // }; // audioRef.value.onPlay = () => { // audioRef.value?.play(); // onInit(audioRef.value, canvasRef.value); // }; // } emit('loadedmetadata', audioRef.value); }; /** 改变播放时间 */ const handleChangeTime = (val: number) => { data.currentTime = val; clearTimeout(data.timer); data.timer = setTimeout(() => { audioRef.value.currentTime = val; data.timer = null; }, 60); }; /** 播放结束 */ const onEnded = () => { data.playState = 'pause'; // emit('ended'); }; let vudio1 = null; const canvas1: any = ref(); const audio1: any = ref(); nextTick(() => { const rect = contetRef.value.getBoundingClientRect() || { width: 200, height: 200 }; vudio1 = new Vudio(audio1.value, canvas1.value, { effect: 'waveform', accuracy: 128, width: rect.width, height: rect.height, waveform: { maxHeight: 160, color: [ [0, '#44D1FF'], [0.5, '#44D1FF'], [0.5, '#198CFE'], [1, '#198CFE'] ], prettify: false } }); vudio1.dance(); }); const calculateSpeed = (element: any) => { let previousBytesLoaded = 0; let timer: any = null; let previousTime = Date.now(); let isWaiting = false; // 缓存检测状态 let isBuffering = false; // 缓存检测计时器 let bufferTimeout: any = null; // 设定一个检测缓存停止的时间间隔,这里我们设置为2500毫秒(2秒) const BUFFER_CHECK_INTERVAL = 2500; function resetDownloadSpeed() { timer = setTimeout(() => { // displayElement.textContent = `视屏下载速度: 0 KB/s`; data.speedInKbps = `0 KB/s`; }, 1500); } function buffterCatch() { // 设定一个计时器,检查是否在指定的时间内再次触发了progress事件 bufferTimeout = setTimeout(() => { if (isBuffering) { // 如果计时器到达且isBuffering仍为true,则认为缓存停止 console.log('停止缓存数据。'); isBuffering = false; data.speedInKbps = ''; } }, BUFFER_CHECK_INTERVAL); } element.addEventListener('progress', () => { const currentTime = Date.now(); const buffered = element.buffered; let currentBytesLoaded = 0; if (buffered.length > 0) { for (let i = 0; i < buffered.length; i++) { currentBytesLoaded += buffered.end(i) - buffered.start(i); } currentBytesLoaded *= element.duration * element.seekable.end(0); // 更精确地近似字节加载量 } // console.log( // 'progress', // currentBytesLoaded, // previousBytesLoaded, // currentBytesLoaded > previousBytesLoaded // ); if (currentBytesLoaded > previousBytesLoaded) { const timeDiff = (currentTime - previousTime) / 1000; // 时间差转换为秒 const bytesDiff = currentBytesLoaded - previousBytesLoaded; // 字节差值 const speed = bytesDiff / timeDiff; // 字节每秒 if (!element.paused) { const kbps = speed / 1024; const speedInKbps = kbps.toFixed(2); // 转换为千字节每秒并保留两位小数 if (kbps > 1024) { data.speedInKbps = `${Number((kbps / 1024).toFixed(2))} M/s`; } else { data.speedInKbps = `${Number(speedInKbps)} KB/s`; } } previousBytesLoaded = currentBytesLoaded; previousTime = currentTime; } if (!element.paused) { // 如果1秒钟没有返回就重置数据 clearTimeout(timer); resetDownloadSpeed(); } if (!isWaiting) { // 如果有缓存检测计时器,则清除它 if (bufferTimeout) { clearTimeout(bufferTimeout); } // 标记为正在缓存 isBuffering = true; buffterCatch(); } }); element.addEventListener('waiting', () => { console.log('waiting'); isWaiting = true; if (!element.paused) { // 如果1秒钟没有返回就重置数据 clearTimeout(timer); resetDownloadSpeed(); } // 如果有缓存检测计时器,则清除它 if (bufferTimeout) { clearTimeout(bufferTimeout); } }); element.addEventListener('canplay', () => { console.log('canplay'); isWaiting = false; // 如果有缓存检测计时器,则清除它 if (bufferTimeout) { clearTimeout(bufferTimeout); } // 标记为正在缓存 isBuffering = true; buffterCatch(); }); element.addEventListener('pause', () => { clearTimeout(timer); // 如果有缓存检测计时器,则清除它 if (bufferTimeout) { clearTimeout(bufferTimeout); } data.speedInKbps = ''; }); // element.addEventListener('error', () => { // element.pause(); // }); }; onMounted(() => { nextTick(() => { calculateSpeed(audioRef.value); }); }); return () => (
{data.afterMa3 && (
)}
{ e.stopPropagation(); }} onTouchmove={(e: TouchEvent) => { emit('close'); }}>
{getSecondRPM(data.currentTime)}
{getSecondRPM(data.duration)}
{ handleChangeTime(val); }} onDragStart={() => { data.dragStatus = true; console.log('onDragStart'); }} onDragEnd={() => { data.dragStatus = false; console.log('onDragEnd'); }} />
emit('close')}>
onToggleAudio()}>
{ data.loop = !data.loop; if (data.loop) { setTimeout(() => { showToast('已打开循环播放'); }, 60); } else { setTimeout(() => { showToast('已关闭循环播放'); }, 60); } }}>
{data.speedInKbps}
); } });