audio标签 用element-plus中的el-progress模拟播放进度
可直接拿来用
播放器相关事件js
老版本显示兼容: 音量滑道不显示样式兼容问题可加input[type="range"] { writing-mode: vertical-lr; direction: rtl; -webkit-appearance: slider-vertical; appearance: slider-vertical; }处理
<script lang="ts" setup>
import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
import { useCounterStore } from '@/stores'
const userStore = useCounterStore();
const audioPlayer:any = ref(null);
const mp3List:any = [{name:'aa',src:'https://lw-sycdn.kuwo.cn/504881085d1eca4eb48b3d7f3c596992/66f8f7b4/resource/30106/trackmedia/M500002QkflO1okifA.mp3'},
{name:'bb',src:'https://webfs.kugou.com/202409291521/0db24266f14d9619da72163ac1ebdca9/v3/3bc78d2da5775382b4858da64872de7c/yp/full/ap1014_us0_mii0w1iw8z2ai2iphcu80ooo2ki81120_pi406_mx676479208_s3837368345.mp3'},
{name:'cc',src:'https://webfs.kugou.com/202409291413/24baa92e27a507f66b28e126f88b0b20/v3/3fb35373b7b200c05679cab6d345d0eb/yp/full/ap1014_us0_mii0w1iw8z2ai2iphcu80ooo2ki81120_pi406_mx676426518_s3681119118.mp3'}]
const volume = ref(50); // 初始音量
const progress = ref(0);
const progressTwo = ref(0);
const duration = ref(0);
const isPlaying = ref(false);
let nextUpdateTime = 0;
let progressUpdateTimer:any = null;
const myDiv:any = ref(null);
const mp3Index = ref(0);
const mp3Name = ref();
userStore.myDiv = myDiv;
// 播放音乐
function play() {
if (audioPlayer.value) {
if (mp3List.length > 0) {
mp3Index.value++;
audioPlayer.value.src = mp3List[0].src;
mp3Name.value = mp3List.shift().name;
isPlaying.value = true;
audioPlayer.value.play();
progressUpdateTimer = setInterval(() => {
updateProgress();
}, 1000);
} else {
stop();
}
}
}
// 暂停音乐
function pause() {
if (audioPlayer.value) {
isPlaying.value = false;
audioPlayer.value.pause();
}
}
function vlume() {
userStore.rangeShow = true;
}
function setVolume(event: Event) {
if (audioPlayer.value) {
audioPlayer.value.volume = volume.value / 100;
}
}
// 更新播放时间
function updateProgress() {
if (audioPlayer.value) {
progress.value = Math.floor(audioPlayer.value.currentTime);
const currentTime = Math.floor(audioPlayer.value.currentTime);
const durationTime = Math.floor(audioPlayer.value.duration);
if (currentTime >= nextUpdateTime) {
progressTwo.value = (currentTime / durationTime) * 100;
nextUpdateTime += 1; // 假设每秒更新一次
}
}
}
// 更新歌曲总时长
function updateDuration() {
if (audioPlayer.value) {
duration.value = Math.floor(audioPlayer.value.duration);
}
}
// 格式化播放时间
const currentTime = computed(() => {
return formatTime(progress.value);
});
// 格式化总时长
const durationTime = computed(() => {
return formatTime(duration.value);
});
// 格式化时间为 mm:ss 格式
function formatTime(seconds: number) {
const minutes = Math.floor(seconds / 60);
const secondsRemainder = Math.floor(seconds) % 60;
return `${minutes.toString().padStart(2, '0')}:${secondsRemainder.toString().padStart(2, '0')}`;
}
// 处理音频播放结束的函数
function handleAudioEnd() {
if(mp3List.length > 0 ){
isPlaying.value = false;
progressTwo.value = 0;
audioPlayer.value.currentTime = 0; // 重置播放时间
progress.value = 0;
nextUpdateTime = 0;
progressTwo.value = 0; // 重置进度条
clearInterval(progressUpdateTimer);
// 这里可以执行其他操作,比如自动播放下一首音乐或者显示播放结束的信息
play()
}
}
// 停止音乐并重置
function stop() {
if (audioPlayer.value) {
isPlaying.value = false;
audioPlayer.value.pause();
audioPlayer.value.currentTime = 0; // 重置播放时间
progress.value = 0; // 重置进度条
nextUpdateTime = 0;
progressTwo.value = 0; // 重置进度条
clearInterval(progressUpdateTimer.value); // 清除定时器
}
}
onMounted(() => {
progressUpdateTimer = setInterval(() => {
updateProgress();
}, 1000); // 每秒更新一次
});
onBeforeUnmount(() => {
clearInterval(progressUpdateTimer);
});
</script>
vue3
<template>
<div class="musicPlayer">
<!-- @timeupdate="updateProgress" -->
<audio ref="audioPlayer" @timeupdate="updateProgress" @loadedmetadata="updateDuration" @ended="handleAudioEnd"></audio>
<img class="playBtn pointer" v-if="isPlaying == false || currentTime == durationTime" @click="play" src="@/assets/images/Latent/playBtn.png" alt="">
<img class="pauseBtn pointer" v-else @click="pause" src="@/assets/images/Latent/pauseBtn.png" alt="">
<img class="stopBtn pointer" @click="stop" src="@/assets/images/Latent/stopBtn.png" alt="">
<el-progress class="range no-animation-progress" :percentage="progressTwo" :duration="duration" :show-text="false"></el-progress>
<div class="musicMessage">
<span class="musicTitle">{{mp3Name}}</span>
<!-- <span class="musictime">{{ progress }} / {{ duration }}</span> -->
<span class="musictime">{{ currentTime }} / {{ durationTime }}</span>
</div>
<div class="volume" ref="myDiv">
<img class="volumeBtn pointer" src="@/assets/images/Latent/vlume.png" @click="vlume" alt="">
<input v-if="userStore.rangeShow" class="volumeShow" type="range" v-model.number="volume" min="0" max="100" @change="setVolume">
</div>
</div>
</template>
css样式
<style >
.musicPlayer{
display: flex;
align-items: center;
position:absolute;
bottom:0;
width:100%;
height: 130px;
background: rgba(0,0,0,0.45);
border-radius: 55px;
.no-animation-progress .el-progress-bar__inner {
transition: none; /* 这里设置 transition 为 none,禁用动画 */
}
.volumeShow{
position:absolute;
right:100px;
bottom:95px;
width:8px;
height:130px;
}
.playBtn{
width:40px;
height:48px;
margin-left: 95px;
margin-right: 40px;
}
.pauseBtn{
width:40px;
height:48px;
margin-left: 95px;
margin-right: 40px;
}
.stopBtn{
width:43px;
height:43px;
margin-right: 40px;
}
.range{
width:1500px;
position:relative;
top:8px;
.el-progress-bar__outer{
height: 12px !important;
border-radius: 5px !important;
background: #313944 !important;
}
}
input[type=range] {
-webkit-appearance: slider-vertical;
}
.musicMessage{
position: absolute;
top:28px;
width:1500px;
left:50%;
margin-left:-700px;
display: flex;
justify-content: space-between;
font-weight: 500;
font-size: 25px;
color: #FFFFFF;
line-height: 35px;
.musictime{
margin-right: 5px;
}
}
.volume{
display:inline-block;
}
.volumeBtn{
width:39px;
height:30px;
margin-left: 40px;
}
}
</style>