uniapp音频播放方法的使用说明
uniapp音频播放方法的使用说明设计思路:1、音频播放可以暂停,继续2、播放完成可以继续播放下一条3、手动切歌上一曲、下一曲4、列表选择想听的音频5、顺序播放,单曲循环,随机播放需要注意的地方:1、音频开始播放签需要先去获取音频的总时长(在没有音频总时长的情况下)然后再播放音频,这里需要等待音频总时长获取成功后再执行音频播放的函数,如果接口返回音频列表,建议把音频总时长一起返回。两个地方:切歌换
uniapp音频播放方法的使用说明
设计思路:
1、音频播放可以暂停,继续
2、播放完成可以继续播放下一条
3、手动切歌上一曲、下一曲
4、列表选择想听的音频
5、顺序播放,单曲循环,随机播放
需要注意的地方:
1、音频开始播放签需要先去获取音频的总时长(在没有音频总时长的情况下)然后再播放音频,这里需要等待音频总时长获取成功后再执行音频播放的函数,如果接口返回音频列表,建议把音频总时长一起返回。两个地方:
切歌换曲函数audio.vue
async changeMusic(witch) {
audioRecorder.playStop();
this.currentTime = 0
switch (this.playType) {
case 1:
break;
case 2:
//witch:1下一曲;0上一曲
if (witch == 1) {
//已经是最后一首歌的情况,在往下一曲就是第一首歌
this.currentIndex + 1 == this.musicList.length ? this.currentIndex = 0 : ++this
.currentIndex
} else {
//已经是第一首歌的情况,在往上一曲就是最后一首歌
this.currentIndex == 0 ? this.currentIndex = this.musicList.length - 1 : --this
.currentIndex
}
break;
default:
let randomNumber = this.getRandomInt(0, this.musicList.length - 1);
this.currentIndex = randomNumber
}
await this.preparation();
this.startPlay();
},
选择想要播放的音频audio.vue
async cutSong(index) {
audioRecorder.playStop();
this.currentIndex = index
await this.preparation();
this.startPlay();
this.isList = false
},
准备要播放的音频信息,主要是为了获取音频的总时长audio.vue
async preparation() {
this.playObj = this.musicList[this.currentIndex]
await audioRecorder.getDurationTwo(this.playObj).then(res => {
this.fullDuration = res.duration
})
},
2、音频开始播放和继续播放使用的是同一个方法函数,只需要设置音频开始播放的时间位置即可,所以调用音频播放的方法时需要把音频路径和开始播放的时间一起传
调用播放音频方法audio.vue
audioRecorder.playVoiceTwo(this.playObj.path, this.currentTime).then(res => {})
封装的音频播放方法methodfile.js
// 音频播放,用于页面只有一条语音的情况
export async function playVoiceTwo(voicePath, playTime) {
return new Promise(resolve => {
// 能多次播放的情况:uni.createInnerAudioContext需要重新获取
innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
// 音频路径
innerAudioContext.src = voicePath;
// 开始播放的位置
innerAudioContext.startTime = playTime
//播放音量
innerAudioContext.volume = profile.volume
innerAudioContext.play();
this.TimeUpdate()
});
}
封装的音频播放方法中// 能多次播放的情况:uni.createInnerAudioContext需要重新获取
innerAudioContext = uni.createInnerAudioContext();
用于音频临时路径能够多次播放
3、音频暂停时需要存储音频暂停的位置时长,方便继续播放时传值。建议把暂停时长传出到页面,方便设置
音频播放暂停methodfile.js
export function playPause() {
return new Promise((resolve, reject) => {
innerAudioContext.pause();
resolve(currentTime)
})
}
4、音频销毁实例,在页面销毁时调用,用于释放空间。该代码中未使用到音频实例销毁。
附上源码:播放部分和列表显示部分写在同一个页面
vue文件:audio.vue
<template>
<view>
<view v-show="!isList">
<!-- 音频名称 -->
<view class="music-title">
{{playObj.name}}
</view>
<!-- 音频封面 -->
<view class="music-cover row-layout">
<image src="/static/image/logo.png" :class="playing?'cover-image':''"></image>
</view>
<!-- 音频操作按钮 -->
<view class="page-top row-layout">
<view class="operate-btn" @click="changeMusic(0)">
<image src="/static/image/gf-previous.png"></image>
<view class="btn_text">上一曲</view>
</view>
<view class="operate-btn" v-show="!playing" @click="startPlay()">
<image src="/static/image/gf-play.png"></image>
<view class="btn_text">播放</view>
</view>
<view class="operate-btn" v-show="playing" @click="pausePlay()">
<image src="/static/image/gf-pause.png"></image>
<view class="btn_text">暂停</view>
</view>
<view class="operate-btn" @click="changeMusic(1)">
<image src="/static/image/gf-next.png"></image>
<view class="btn_text">下一曲</view>
</view>
</view>
<!-- 音频播放模式 -->
<view class="page-footer row-layout">
<view class="other-btn" v-show="playType==3" @click="changeType()">
<image src="/static/image/random.png"></image>
</view>
<view class="other-btn" v-show="playType==2" @click="changeType()">
<image src="/static/image/listloop.png"></image>
</view>
<view class="other-btn" v-show="playType==1" @click="changeType()">
<image src="/static/image/singlecycle.png"></image>
</view>
<view class="other-btn" @click="isList = true">
<image src="/static/image/playlistMusic.png"></image>
</view>
</view>
<view class="divider-line"></view>
</view>
<!-- 音频列表 -->
<view class="pages-list" v-show="isList">
<!-- 可滚动区域 -->
<scroll-view :scroll-top="scrollTop" scroll-y="true" @scroll="scroll" class="scroll-Y">
<view>
<view class="list-item row-layout" v-for="(item,index) in musicList" :key="index"
@click="cutSong(index)">
<!-- 序号 -->
<view>{{index>=9?(index+1):'0'+(index+1)}}</view>
<image src="/static/image/logo.png"></image>
<view>{{item.name}}</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import * as audioRecorder from '@/audioRecorder/methodfile.js'; //音频封装的方法文件
export default {
props: {
musicList: {
type: Array,
default: []
}
},
data() {
return {
playing: false, //播放状态
playObj: {}, //正在播放的信息
currentTime: 0, //播放开始位置时间
currentIndex: 0, //正在播放的索引
fullDuration: 0, //音频总时长
playType: 2, //播放模式默认2:列表循环播放,1:单曲循环,3:随机播放
isList: false, //是否显示音频列表
scrollTop: 0, //滚动区域的顶部距离
old: {
scrollTop: 0
},
}
},
mounted() {
this.preparation();
},
methods: {
//准备要播放的音频信息,主要是为了获取音频的总时长
async preparation() {
this.playObj = this.musicList[this.currentIndex]
await audioRecorder.getDurationTwo(this.playObj).then(res => {
this.fullDuration = res.duration
})
},
//开始播放
startPlay() {
this.playing = true
audioRecorder.playVoiceTwo(this.playObj.path, this.currentTime).then(res => {})
setTimeout(() => {
this.changeMusic(1);
}, this.fullDuration * 1000)
},
//暂停播放
pausePlay() {
this.playing = false
audioRecorder.playPause().then(res => {
this.currentTime = res
})
},
//切歌换曲
async changeMusic(witch) {
audioRecorder.playStop();
this.currentTime = 0
switch (this.playType) {
case 1:
break;
case 2:
//witch:1下一曲;0上一曲
if (witch == 1) {
//已经是最后一首歌的情况,在往下一曲就是第一首歌
this.currentIndex + 1 == this.musicList.length ? this.currentIndex = 0 : ++this
.currentIndex
} else {
//已经是第一首歌的情况,在往上一曲就是最后一首歌
this.currentIndex == 0 ? this.currentIndex = this.musicList.length - 1 : --this
.currentIndex
}
break;
default:
let randomNumber = this.getRandomInt(0, this.musicList.length - 1);
this.currentIndex = randomNumber
}
await this.preparation();
this.startPlay();
},
// 生成随机数,用于随机播放
getRandomInt(min, max) {
let minnum = Math.ceil(min);
let maxnum = Math.floor(max);
return Math.floor(Math.random() * (maxnum - minnum + 1)) + minnum;
},
//切换播放方式
changeType() {
this.playType == 3 ? this.playType = 1 : ++this.playType
},
// 选择想要播放的音频
async cutSong(index) {
audioRecorder.playStop();
this.currentIndex = index
await this.preparation();
this.startPlay();
this.isList = false
},
// 滚动
scroll: function(e) {
this.old.scrollTop = e.detail.scrollTop
},
}
}
</script>
<style lang="scss" scoped>
.music-title {
font-size: 38rpx;
font-weight: 600;
text-align: center;
}
.music-cover {
margin-top: 12%;
justify-content: center;
image {
width: 170rpx;
/* 设置图像宽度,根据需要调整 */
height: 170rpx;
/* 设置图像高度,根据需要调整 */
border-radius: 50%;
}
.cover-image {
animation: rotateAnimation 3s linear infinite;
/* 设置动画:名称 时间 函数 迭代次数 */
}
/* 定义旋转动画关键帧 */
@keyframes rotateAnimation {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
}
.page-top {
margin-top: 16%;
justify-content: space-between;
.operate-btn {
text-align: center;
image {
width: 66rpx;
height: 66rpx;
}
.btn_text {
font-size: 30rpx;
}
}
}
.page-footer {
margin-top: 16%;
justify-content: flex-end;
.other-btn {
image {
width: 55rpx;
height: 55rpx;
margin: 0 40rpx;
}
}
}
.divider-line {
position: absolute;
top: 50%;
left: 0;
width: 100vw;
height: 6rpx;
background: gray;
}
.pages-list {
.scroll-Y {}
.list-item {
padding-bottom: 30rpx;
margin-bottom: 30rpx;
border-bottom: 2rpx solid #ededed;
image {
width: 66rpx;
height: 66rpx;
margin: 0 38rpx;
}
}
}
</style>
方法文件:methodfile.js
import profile from './profile.js';
// 全局定义音频
let innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
let currentTime = 0
/**
* 音频播放、暂停、继续、结束方法
*/
// 音频播放,用于页面只有一条语音的情况
export async function playVoiceTwo(voicePath, playTime) {
return new Promise(resolve => {
// 能多次播放的情况:uni.createInnerAudioContext需要重新获取
innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
// 音频路径
innerAudioContext.src = voicePath;
// 开始播放的位置
innerAudioContext.startTime = playTime
//播放音量
innerAudioContext.volume = profile.volume
innerAudioContext.play();
this.TimeUpdate()
});
}
//计算音频时长,用于页面只有一条语音并要展示语音时长的情况
export async function getDurationTwo(item) {
return new Promise(resolve => {
const audioContext = uni.createInnerAudioContext();
// 设置音频的路径
audioContext.src = item.path;
// 监听音频加载完成事件
audioContext.onCanplay(() => {
// 获取音频的时长(单位:秒)
const duration = Math.round(audioContext.duration);
const min = Math.floor(duration / 60); // 获取分钟数
const second = (duration % 60) < 10 ? '0' + (duration % 60) : (duration % 60);
const times = min + ':' + second
// 将时长打印到控制台或进行其他操作
Object.assign(item, {
duration: audioContext.duration,
seconds: times
});
// 计算完时长后销毁创建的音频实例
audioContext.destroy();
resolve(item); // 异步操作完成后调用resolve,标识异步操作完成
});
});
}
// 音频播放进度更新事件,主要是获取播放的位置,继续播放时连着暂停的位置继续往下播放
export function TimeUpdate() {
// 监听音频播放进度变化事件
innerAudioContext.onTimeUpdate(() => {
// 获取当前音频播放的时间
currentTime = innerAudioContext.currentTime;
});
}
// 音频播放暂停
export function playPause() {
return new Promise((resolve, reject) => {
innerAudioContext.pause();
resolve(currentTime)
})
}
// 音频播放停止
export function playStop() {
return new Promise((resolve, reject) => {
// 确保recorderManager对象被成功初始化后再调用stop方法
if (innerAudioContext) {
innerAudioContext.stop();
resolve()
} else {
reject('innerAudioContext未成功初始化');
}
})
}
// 音频实例销毁
export function playDestroy() {
innerAudioContext.destroy();
}
配置文件:profile.js
let DURATION = 180000 //录音时长,毫秒
let VOLUME = 0.2 //音频播放音量0~1
const profile = {
duration: DURATION,
volume: VOLUME
};
export default profile
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)