总体是使用uniapp的uni.createInnerAudioContext()来制作的,所以如果官方的api所支持的平台,那么这个也支持
贴出的代码不是组件的形式,可自行封装
全部代码如下:
<template>
<view class="contentBox">
<view class="audio-item" v-for="(item,k) in audList" :key="k">
<view class="item-left"><!-- :style="{backgroundImage: 'url(' + item.pic + ')'}" -->
<view @click="toPlayAudio(k,item.src)" class="play-btn">
<image style="width: 50rpx;height: 50rpx;" v-if="!item.isPlay"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAbFJREFUWEfFl4ttQjEMRe1NyiQtkxQmaZmkbFI6SdnE6FZO6hfysaNILxICicQ+ufEnYdp58M7+KQQgIi9EdCKiVyLCb3zuugl8/xDRjZlv3o25AETkjYi+1KHHNmAuzHwdTe4C6I7hGAAzAyBHZk4qPdloAuiuv2e8Fmvg/Nw6lirAQueJpQnxBKCy/y7YeWmiehw1AMjeO3MYQvTPDGTI0S7cAIgIUgxB1xzMzCYdPyYoEJQ5TUuA4e6Z+ZCcisgnEUUh7tZGBnAG3mYxQFQNgEeOJatgAYbyo+pZeqNEqpBeNVCkoN5/KRaRkfyYXwWYOJIcjFYBpN5Ixi5A4EiyneUACoE07lXRKoA4UmqogAIMswPpvDwG1HkoluwRhBaWagU755WZz6UCQ9k6aehJYcuM7vh3V7AKIANGTahWiFC6ARAZh3RHmC7FQcktXL0UO9MH0y5qzVv1SmXazSgQxRG57dx+Ow5UshkA34XEQIwCMgqxkT4t7l1KkRXRNluDil9Kiza7z7XcbkWvau+B98Gah0mj3KanGf5G1yufZiizzYdIadP1NItGW2T+7gAPZz/cIRYk1noAAAAASUVORK5CYII=">
</image>
<image style="width: 50rpx;height: 50rpx;" v-else
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAadJREFUWEfNVwtOwzAMfT4J7CTQk8BOAjsJ5SSUk1BOYvaieEq7tHGqdCNStUmJ7ZfnT2xBxVLVRwCvAJ4A8D+/MargL79PERm8aqV0MDH6Vjqb7AcgZ4C9iBjArPgqAFV9B1BjeG7EGKEeP4B46w8AzxW3XjtKIF2OjSsGovGv6N9G9oOaLIgJgB2N20WuQMwB8OataF9ibxSRg21eADQIuBp3MTuOFEgBqEODpddDrAepSA/gF8CLI34urggAVJURzwJTWkcRoSHKTNwlIqaLLuReaQUWTMhzeypsCSDEgqgqb04GPKslANrrCMBLf2sGqO9EADWp15qBgQB+HFFr7mkNYCQAbwDu4YK7A8C/cMHdg7Cm6WgdhD1d4C2dewRhKERsLJmKntWUAb4ftY/R6SwS+rt5/Uh0eUv75DHysmDPMTHMm1W24t/O55jyB/aIaT/gRe5xVenMhckUAFlo2QkvgRhEpLPNmzelaT9IELduy5lFk7EtOxntMJhMaE99sziabZwJ537fNpqlWjYCKRrOBuFa7kQgzBRru3PjOesA6XaP53+/FzDLAjxB3gAAAABJRU5ErkJggg==">
</image>
</view>
</view>
<view class="item-right">
<text class="title-text">{{item.title}}</text>
<text class="sub-text">{{item.subtitle}}</text>
<view class="progress-bar">
<view class="slider-item">
<slider @change="change($event,k)" :value="item.playDuration" :max="item.duration"
activeColor="#3DD95F" backgroundColor="#E6E6E6" block-size="8" block-color="#fff"></slider>
</view>
<text class="time-text">{{item.playDuration,item.duration|formatPlayDate}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: ['audios'],
data() {
return {
audIndex: -1, //当前播放列表下标
innerAudioContext: null, //音频播放实例
/**
* title 音频名称
* subtitle 副标题
* duration 音频时长(s)
* src 音频播放地址
* pic 音频封面图
* isPlay 播放状态(true 播放中)
* playDuration 播放时长(用来记录该音频播放位置,或者通过滑动slide改变播放位置)
*/
audList: [
{
title: '音频1',
subtitle:'2024-08-16',
duration:"107.970583",
src: 'http://music.163.com/song/media/outer/url?id=2616685129.mp3',
pic: 'http://p2.music.126.net/0vdbPw8RHhsDidc4Odp4gw==/109951166620193623.jpg',
isPlay:false,
playDuration:0
},{
title: '音频1',
subtitle:'2024-08-16',
duration:"107.970583",
src: 'http://music.163.com/song/media/outer/url?id=2616685129.mp3',
pic: 'http://p2.music.126.net/0vdbPw8RHhsDidc4Odp4gw==/109951166620193623.jpg',
isPlay:false,
playDuration:0
},{
title: '音频1',
subtitle:'2024-08-16',
duration:"107.970583",
src: 'http://music.163.com/song/media/outer/url?id=2616685129.mp3',
pic: 'http://p2.music.126.net/0vdbPw8RHhsDidc4Odp4gw==/109951166620193623.jpg',
isPlay:false,
playDuration:0
},{
title: '音频1',
subtitle:'2024-08-16',
duration:"107.970583",
src: 'http://music.163.com/song/media/outer/url?id=2616685129.mp3',
pic: 'http://p2.music.126.net/0vdbPw8RHhsDidc4Odp4gw==/109951166620193623.jpg',
isPlay:false,
playDuration:0
},
] //音频播放列表
}
},
//页面销毁事件
beforeDestroy() {
//组件销毁时将音频播放器也销毁
if (this.innerAudioContext != null) {
this.innerAudioContext.pause()
this.innerAudioContext.destroy()
this.innerAudioContext = null
}
},
methods: {
//播放音频
toPlayAudio(i, src) {
//判断是否为首次播放
if (this.innerAudioContext != null) {
//判断改音频是否播放中,播放中则暂停
if (this.audList[i].isPlay == true) {
this.innerAudioContext.pause()
this.audList[i].isPlay = false
return
} else {
//播放新的音频文件,提前销毁实例,避免-99错误(官网建议的https://uniapp.dcloud.net.cn/api/media/audio-context.html#createinneraudiocontext)
this.innerAudioContext.pause()
this.innerAudioContext.destroy()
this.innerAudioContext = null
//将音频列表的状态都改为未播放
this.audList.map(item => {
item.isPlay = false
})
}
}
//存储播放下标
this.audIndex = i
//创建实例
this.innerAudioContext = uni.createInnerAudioContext();
//播放
this.innerAudioContext.src = src
//设置开始播放位置
this.innerAudioContext.startTime = this.audList[i].playDuration
this.innerAudioContext.play()
//更改播放状态
this.audList[i].isPlay = true
//监听报错信息
this.innerAudioContext.onError((res) => {
console.log(res.errMsg);
console.log(res.errCode);
});
//监听自然播放结束事件,并改变播放状态
this.innerAudioContext.onEnded((res) => {
this.audList[this.audIndex].isPlay = false
this.audList[this.audIndex].playDuration = 0
})
//监听播放进度事件
this.innerAudioContext.onTimeUpdate(() => {
this.audList[this.audIndex].playDuration = this.innerAudioContext.currentTime
})
},
//slide滑动事件
change(e,index) {
//将滑动后的值赋值给对应音频列表下标的playDuration
this.audList[index].playDuration = e.detail.value
//判断innerAudioContext是否有实例
if (this.innerAudioContext != null) {
//如果是正在播放的就改变播放位置
if(index == this.audIndex){
this.innerAudioContext.seek(e.detail.value)
}
}
},
},
filters: {
//将秒数格式化为类似 02:23/05:02 前面是当前播放位置,后面是总时长
//可根据自己需求随意更改
formatPlayDate(pDate, duration) {
let time = Math.floor(parseInt(pDate))
let total = Math.floor(parseInt(duration))
//格式化已播放时长
let timeMin = Math.floor(time / 60) > 9 ? Math.floor(time / 60) : '0' + Math.floor(time / 60)
let timeSec = (time % 60) > 9 ? (time % 60) : '0' + (time % 60)
//格式化总时长
let totalMin = Math.floor(total / 60) > 9 ? Math.floor(total / 60) : '0' + Math.floor(total / 60)
let totalSec = (total % 60) > 9 ? (total % 60) : '0' + (total % 60)
return `${timeMin} : ${timeSec} / ${totalMin} : ${totalSec}`
}
}
}
</script>
<style lang="scss" scoped>
//更改slider样式,如果是微信小程序记得加
//options: {
// styleIsolation: 'shared', // 解除样式隔离
//}
/deep/ uni-slider {
margin: 0 !important;
}
/deep/ uni-slider .uni-slider-thumb {
margin-left: 0 !important;
border: 1px solid #3DD95F;
}
.audio-item {
margin-bottom: 20rpx;
box-shadow: 0 0 6rpx 1rpx rgba(0, 0, 0, 0.1);
background: #fff;
display: flex;
flex-direction: row;
}
.title-text {
font-size: 24rpx;
font-weight: bold;
}
.sub-text {
font-size: 20rpx;
color: #9E9E9E;
}
.time-text {
font-size: 18rpx;
color: #BEBEBE;
display: flex;
margin: 0 20rpx;
}
.item-left {
width: 128rpx;
height: 128rpx;
background: url('/static/pic.png');
background-repeat: no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
}
.item-right {
flex-grow: 1;
padding: 10rpx 0;
display: flex;
flex-direction: column;
justify-content: space-between;
.progress-bar {
display: flex;
align-items: center;
.slider-item {
flex-grow: 1;
}
}
}
</style>