基于vue3和audio封装的简易音频播放器

embedded/2024/12/21 23:47:14/

样式如图所示
在这里插入图片描述

<template><div class="audio-player"><div class="player_top" flex-ac  flex-justify-between ><div class="fileName  genericTitle" fs-28 l-height-32 height-64 pr-42 flex-ac><span class="text-line-2">{{ fileName }}</span></div><div class="play_btn"><div class="toPlay" width-60 height-60 v-if="!playStatus" @click="onPlay"></div><div class="toStop" width-60 height-60 v-else @click="onPause"></div></div></div><div class="player_time" fs-14 mt-13 mb-8 flex  flex-justify-between><span class="play_audioCurrent" style="color:#1e62d9"> {{ transTime(audioCurrent) }} </span><span class="play_audioDuration" style="color:#A5A5A5"> {{ transTime(audioDuration) }} </span></div><div class="play_progress" pl-13 pr-13><el-slider v-model="playProgress" :show-tooltip="false" @input="onProgressChange" /></div></div><audio ref="audioRef" :src="url" @canplay="onCanplay" @timeupdate="updateProgress" @ended="playEnd" />
</template><script setup lang="ts">
import { ref, onBeforeMount, onUnmounted, onMounted, watch, nextTick } from 'vue';const props = defineProps({// 音频地址url: {type: String,required: true},// 音频名称fileName: {type: String,required: false}
});
const emits = defineEmits(['play', 'timeupdate']);
watch(() => props.url,newVal => {if (newVal) {nextTick(() => {initAudio();});}}
);const speedVisible = ref<boolean>(false); // 设置音频播放速度弹窗
const audioRef = ref<HTMLAudioElement | null>(null); // 音频标签对象
const activeSpeed = ref(1); // 音频播放速度
const audioDuration = ref(0); // 音频总时长
const audioCurrent = ref(0); // 音频当前播放时间
const audioVolume = ref(1); // 音频声音,范围 0-1
const playStatus = ref<boolean>(false); // 音频播放状态:true 播放,false 暂停
const playProgress = ref(0); // 音频播放进度const initAudio = () => {if (audioRef.value) {audioRef.value.load();playStatus.value = false;playProgress.value = 0;audioRef.value.src = props.url;}
};// 音频加载完毕的回调
const onCanplay = () => {audioDuration.value = audioRef?.value.duration || 0;
};
const onPlay = async () => {// 音频播放完后,重新播放if (transTime(audioCurrent.value) === transTime(audioDuration.value)) audioRef.value.currentTime = 0;await audioRef.value.play();playStatus.value = true;audioDuration.value = audioRef.value.duration;emits('play');
};
const onPause = () => {audioRef.value.pause();playStatus.value = false;
};
// const onChangeSpeed = (value: number) => {
//   activeSpeed.value = value;
//   // 设置倍速
//   audioRef.value.playbackRate = value;
//   speedVisible.value = false;
// };
// const onHandleSpeed = () => {
//   speedVisible.value = !speedVisible.value;
// };
// // 设置声音
// const onSetVolume = (value: number) => {
//   audioRef.value.volume = value;
//   audioVolume.value = value;
// };
// 音频播放时间换算
const transTime = (value: number) => {let time = '';let h = parseInt(String(value / 3600));value %= 3600;let m = parseInt(String(value / 60));let s = parseInt(String(value % 60));if (h > 0) {time = formatTime(h + ':' + m + ':' + s);} else {time = formatTime(m + ':' + s);}return time;
};
// 格式化时间显示,补零对齐
const formatTime = (value: string) => {let time = '';let s = value.split(':');let i = 0;for (; i < s.length - 1; i++) {time += s[i].length == 1 ? '0' + s[i] : s[i];time += ':';}time += s[i].length == 1 ? '0' + s[i] : s[i];return time;
};
const onTimeUpdate = () => {if (audioRef.value) {audioCurrent.value = audioRef.value.currentTime;const progressPercentage = (audioRef.value.currentTime / audioRef.value.duration) * 100;emits('timeupdate', {currentTime: audioCurrent.value,duration: audioDuration.value,progress: progressPercentage});}
};
const onProgressChange = (value: number) => {// if (!value) {//   return;// }console.log(value,'value');audioRef.value.currentTime = (value / 100) * audioDuration.value;
};
const updateProgress = (e) => {// console.log(e,'e');onTimeUpdate();const value = e.target.currentTime / e.target.duration;if (audioRef.value.play) {playProgress.value = value * 100;audioCurrent.value = audioRef.value.currentTime;}
};
const playEnd = () => {playStatus.value = false;
};
// onMounted(() => {
//   initAudio();
// });
onBeforeMount(() => {});
onUnmounted(() => {
});
</script><style lang="scss" scoped>
.audio-player {width: 100%;height: 193px;background: #ffffff;border: 10px solid #c5e9ff;border-radius: 20px;padding: 26px 26px 0 26px;box-sizing: border-box;display: flex;flex-direction: column;align-items: center;.player_top{width: 100%;}.player_time{width: 100%;}.play_progress{width: 100%;::v-deep(.el-slider__runway){height: 10px;border-radius: 6px;background-color: #e5e5e5;.el-slider__bar{height: 10px;border-radius: 6px;background: linear-gradient(270deg,#53c0ff, #3870ff);}.el-slider__button-wrapper{top: -13px;}.el-slider__button{width: 26px;height: auto !important;aspect-ratio: 1 !important;background-color: #1E62D9;border: px2vw(4) solid #ffffff;box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.16);}}}.play-icon {width: 60px;height: 60px;// margin-right: 7px;cursor: pointer;}.play-time {}.play-progress {width: 160px;height: 4px;background-color: #323547;box-shadow: inset 0px 1px 0px 0px #20222d;border-radius: 2px;margin-right: 16px;position: relative;.play-current-progress {height: 4px;background: #00e5ff;border-radius: 2px;position: absolute;top: 0;left: 0;}}.play-voice {width: 20px;height: 20px;margin-right: 14px;cursor: pointer;}.play-speed {cursor: pointer;color: #00e5ff;}.fileName {}.play_btn {cursor: pointer;.toPlay {background: url('@/assets/images/icon_play_audio@2x.png') no-repeat;background-size: 100% 100%;background-origin: border-box;background-clip: content-box;&:hover {background: url('@/assets/images/icon_play_audio_h@2x.png') no-repeat;background-size: 100% 100%;background-origin: border-box;background-clip: content-box;}}.toStop {background: url('@/assets/images/icon_stop_audio@2x.png') no-repeat;background-size: 100% 100%;background-origin: border-box;background-clip: content-box;&:hover {background: url('@/assets/images/icon_stop_audio_h@2x.png') no-repeat;background-size: 100% 100%;background-origin: border-box;background-clip: content-box;}}}
}
</style>

使用

              <AudioPlayer:url="currentResource?.resourceUrl":fileName="currentResource?.resourceName"@play="playMedia"@timeupdate="toUpdatePlayMediaTime"/>// 音视频触发播放
const playMedia = () => {// console.log(currentResource.value, 'playMedia开始播放');
};
// 音视频播放进度
const toUpdatePlayMediaTime = e => {if (e.progress > 85 && currentResource.value.completeStatus === 0) {// 音视频播放进度大于85则该资源标记为学习完成}
};

http://www.ppmy.cn/embedded/100604.html

相关文章

《机器学习》—— 通过下采样方法实现逻辑回归分类问题

文章目录 一、什么是下采样方法&#xff1f;二、通过下采样方法实现逻辑回归分类问题三、下采样的优缺点 一、什么是下采样方法&#xff1f; 机器学习中的下采样&#xff08;Undersampling&#xff09;方法是一种处理不平衡数据集的有效手段&#xff0c;特别是在数据集中某些类…

搜维尔科技:Mnaus VR数据手套-我们正在最先进的手部动作捕捉技术来突破机器人科学的界限

Mnaus VR数据手套-我们正在最先进的手部动作捕捉技术来突破机器人科学的界限 搜维尔科技&#xff1a;Mnaus VR数据手套-我们正在最先进的手部动作捕捉技术来突破机器人科学的界限

僵尸进程的基础学习

1、概念 僵尸进程指的是处于僵尸态的进程&#xff0c;这种进程无法进行调度&#xff0c;但其所占用的系统资源并未被释放。僵尸态是进程生命周期的必经阶段&#xff0c;是无法避免的&#xff0c;但为了节约系统资源&#xff0c;应尽快清理腾出僵尸态进程所占用的内存资源。 2、…

sql盲注python脚本学习 (基于bWAPP靶场)

全局部分 # 数组转字符串 from shlex import join # 请求 import requests # 记时 import timer requests.session() 登录 def login():login_url http://127.0.0.1:1234/login.phpparams dict(loginbee,passwordbug,security_level0,formsubmit)res r.post(login_url,…

Pod基础使用

POD基本操作 1.Pod生命周期 在Kubernetes中&#xff0c;Pod的生命周期经历了几个重要的阶段。下面是Pod生命周期的详细介绍&#xff1a; Pending&#xff08;待处理&#xff09;: 调度: Pod被创建后&#xff0c;首先进入“Pending”状态。此时&#xff0c;Kubernetes的调度器…

Vue2的16种传参通信方式

前言 先直入主题列出有哪些传参方式&#xff0c;下面再通过事例一一讲解。 props(父传子) $emit与 v-on (子传父) EventBus (兄弟传参) .sync与 update: (父子双向) v-model (父子双向) ref $children与 $parent $attrs与 $listeners (爷孙双向) provide与 inject (多层传参) …

【ORACLE】 ORA-01691: Lob 段无法通过 8192 (在表空间 XXX_SPACE 中) 扩展

ORA-01691错误通常表示Oracle数据库在尝试扩展LOB段时无法为表空间分配更多的空间。这个问题通常由表空间容量不足引起。根据搜索结果&#xff0c;以下是几种可能的解决方案&#xff1a; 检查并扩大表空间&#xff1a;首先&#xff0c;确认表空间是否已经达到其最大容量。可以使…

JS 和 ES6 补充学习

1、JS对象-自定义对象 let 对象名 {属性名1&#xff1a;属性值1&#xff0c;属性名2&#xff1a;属性值2&#xff0c;属性名3&#xff1a;属性值3&#xff0c;函数名称&#xff1a;function&#xff08;形参列表&#xff09;{}&#xff0c;函数名称&#xff08;形参列表&…