uniapp音频播放方法的使用说明

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
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值