<template>
<div v-for="(item, index) in list" :key="index">
<div class="audio-player">
<img
src="../.../assets/images/home/shopping"
alt=""
class="play-icon"
@click="onTogglePlay(index)"
v-if="!isPlaying(index)"
/>
<img
src="../.../assets/images/home/shopping"
alt=""
class="play-icon"
@click="onTogglePlay(index)"
v-else
/>
<span class="play-time">
{{ transTime(audioCurrent[index]) }}/{{ transTime(audioDuration[index]) }}
</span>
<div class="play-progress">
<div
class="play-current-progress"
:style="{ width: `${playProgress[index]}%` }"
></div>
</div>
<img
src="../.../assets/images/home/shopping"
alt=""
class="play-voice"
v-if="audioVolume[index] === 1"
@click="onSetVolume(index, 0)"
/>
<img
src="../.../assets/images/home/shopping"
alt=""
class="play-voice"
v-else
@click="onSetVolume(index, 1)"
/>
<el-popover v-model:visible="speedVisible[index]" placement="top" :width="50">
<div
v-for="speedItem in speedList"
:key="speedItem.value"
@click="onChangeSpeed(index, speedItem.value)"
style="margin-bottom: 17px; cursor: pointer; text-align: center"
>
<span>{{ speedItem.label }}</span>
</div>
<template #reference>
<span
class="play-speed"
@click="onHandleSpeed(index)"
>{{ activeSpeed[index] }}x</span>
</template>
</el-popover>
</div>
<audio :ref="setAudioRef(index)" :src="item.url" @canplay="onCanplay(index)" @timeupdate="onTimeUpdate(index)"></audio>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const list = ref([
{ url: 'https://jbkj.obs.cn-east-3.myhuaweicloud.com/data/audioFile/%E5%91%A8%E6%9D%B0%E4%BC%A6-%E4%B8%8A%E6%B5%B7%E4%B8%80%E4%B9%9D%E5%9B%9B%E4%B8%89.mp3' },
{ url: 'https://jbkj.obs.cn-east-3.myhuaweicloud.com/data/audioFile/%E5%91%A8%E6%9D%B0%E4%BC%A6-%E4%B8%8A%E6%B5%B7%E4%B8%80%E4%B9%9D%E5%9B%9B%E4%B8%89.mp3' },
// 你可以在这里添加更多的音频URL
]);
const audioRefs = ref([]);
const playStatus = ref([]);
const audioCurrent = ref([]);
const audioDuration = ref([]);
const playProgress = ref([]);
const audioVolume = ref([]);
const speedVisible = ref([]);
const activeSpeed = ref([]);
const speedList = ref([
{ value: 0.5, label: '0.5x' },
{ value: 1, label: '1x' },
{ value: 1.5, label: '1.5x' },
{ value: 2, label: '2x' }
]);
// 初始化状态
onMounted(() => {
list.value.forEach((_, index) => {
playStatus.value[index] = false;
audioCurrent.value[index] = 0;
audioDuration.value[index] = 0;
playProgress.value[index] = 0;
audioVolume.value[index] = 1;
speedVisible.value[index] = false;
activeSpeed.value[index] = 1;
});
});
// 设置音频引用
const setAudioRef = (index) => (el) => {
audioRefs.value[index] = el;
};
const onTogglePlay = (index) => {
const audio = audioRefs.value[index];
if (audio) {
if (isPlaying(index)) {
audio.pause();
playStatus.value[index] = false;
} else {
onStopAllAudio();
audio.play();
playStatus.value[index] = true;
}
}
};
const onStopAllAudio = () => {
audioRefs.value.forEach((audio, index) => {
if (audio && isPlaying(index)) {
audio.pause();
playStatus.value[index] = false;
}
});
};
const isPlaying = (index) => {
return playStatus.value[index] === true;
};
const onCanplay = (index) => {
const audio = audioRefs.value[index];
if (audio) {
audioDuration.value[index] = audio.duration;
}
};
const onTimeUpdate = (index) => {
const audio = audioRefs.value[index];
if (audio) {
audioCurrent.value[index] = audio.currentTime;
playProgress.value[index] = (audioCurrent.value[index] / audioDuration.value[index]) * 100;
}
};
const onSetVolume = (index, volume) => {
const audio = audioRefs.value[index];
if (audio) {
audio.volume = volume;
audioVolume.value[index] = volume;
}
};
const onChangeSpeed = (index, speed) => {
const audio = audioRefs.value[index];
if (audio) {
audio.playbackRate = speed;
activeSpeed.value[index] = speed;
speedVisible.value[index] = false;
}
};
const onHandleSpeed = (index) => {
speedVisible.value[index] = !speedVisible.value[index];
};
const transTime = (time) => {
// 转换时间格式
const minutes = Math.floor(time / 60);
const seconds = Math.floor(time % 60);
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
};
</script>
<style lang="scss" scoped>
.audio-player {
width: 378px;
height: 52px;
background: linear-gradient(180deg, #505572 0%, #383b4f 100%);
border-radius: 8px;
padding: 9px 11px;
margin: 40px 26px 0;
box-sizing: border-box;
display: flex;
align-items: center;
.play-icon {
width: 34px;
height: 34px;
margin-right: 7px;
cursor: pointer;
}
.play-time {
width: 72px;
display: inline-block;
margin-right: 16px;
}
.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;
}
}
</style>
vue3+ts 音频播放功能(多个音频播放器)
于 2024-06-14 08:47:59 首次发布