前言

之前写了一个音频播放器,但是没时间去优化,最近又有一个需求,希望能够支持背景播放,但是之前使用的是innerAudio,不能够实现背景播放,于是干脆就使用backgroundAudioManager来重新实现了一下音频播放器,并且优化了一下,使得第一次点击进度条时能够直接从点击位置开始播放音频,播放完成后进度条会归零并暂停播放;将js封装了一下便于调用

预览图

代码片段

微信官方所推荐的使用方式(点击后打开开发工具):代码片段

详细代码

以下为具体的页面代码,如果上方代码片段链接失效,请自行手动复制:

关键代码,audioManager.js

//audioManager.js
//2019年8月15日09:52:09
// 实现的功能
//1.进入后获取音频时长; 2.播放暂停 3.进度条自动滚动,播放时间自动增加 4.在播放时拖动进度条后可跳转播放 5.播放完成后进度条归零并暂停//bug&tip
//1.由于微信API wx.getBackgroundAudioManager();创建的背景音频对象在设置src后不能立刻pause();
//  所以获取duration时使用了 wx.createInnerAudioContext();
//  在用户点击播放按钮时才创建背景音频
//2.使用时,请按照微信官方文档,在app.json中配置支持背景播放的以下字段
//  "requiredBackgroundModes":["audio"]//获取全局背景音乐管理器
const manager = wx.getBackgroundAudioManager();
//存储当前播放歌曲信息
let audioData = {src: '',title: '',singer: '',epname: '',coverImgUrl: '',webUrl: '',duration: 0,startTime: 0
};
let audioInterval;
//是否需要重置数据
let resetAudio = true;
const init = (e, t) => {//初始化播放器if (!e.src || !e.title) {return;}audioData.src = e.src || '';audioData.title = e.title || '';audioData.singer = e.singer || '';audioData.epname = e.epname || '';audioData.coverImgUrl = audioData.coverImgUrl || '';audioData.webUrl = e.webUrl || '';audioData.startTime = e.startTime || 0;resetAudio = true;
}const createAudio = (e, t) => {//创建音频播放if (!e.src) {alert('没有音频地址')return;}setAudio(e, t);clearInterval(audioInterval);audioInterval = setInterval(() => {let backgroundAudio = t.data.backgroundAudio;backgroundAudio.isPlaying = !manager.paused;t.setData({backgroundAudio})if (!manager.paused) {let e = {currentTime: manager.currentTime}changeAudioProgressBar(e, t);}}, 1000);manager.onError((err) => {console.log('播放错误');console.log(err);})manager.onEnded(() => {//播放完成resetAudio = true;changeAudioProgressBar({ progress: 0 }, t);pause(t);})
}const getDuration = (e, t) => {//获取音频总时长if (!e.src) {return;}const innerAudioContext = wx.createInnerAudioContext();//用于获取durationinnerAudioContext.src = e.src;//设置srcinnerAudioContext.play();//播放一次以获取音频信息innerAudioContext.pause();//暂停innerAudioContext.onCanplay(() => {var durationInterval = setInterval(() => {if (innerAudioContext.duration) {audioData.duration = innerAudioContext.duration;let backgroundAudio = t.data.backgroundAudio;backgroundAudio.duration = innerAudioContext.duration;var min = parseInt(innerAudioContext.duration / 60), sec = parseInt(innerAudioContext.duration % 60);//小程序无法使用padstart,采用以下方式补全时间格式if (min.toString().length == 1) {min = `0${min}`;} else {min = `${min}`}if (sec.toString().length == 1) {sec = `0${sec}`;} else {sec = `${sec}`}backgroundAudio.durationTime = `${min}:${sec}`;t.setData({backgroundAudio})clearInterval(durationInterval);}}, 500)})
}const seek = (e, t) => {//跳转到该进度播放if (!(e.currentTime || e.progress || e.currentTime == 0 || e.progress == 0)) {console.log('没有参数,无法跳转');return;}if (resetAudio) {if (e.currentTime || e.currentTime == 0) {audioData.startTime = e.currentTime;} else {audioData.startTime = parseInt(e.progress * audioData.duration / 100)}} else {if (e.currentTime || e.currentTime == 0) {manager.seek(parseInt(e.currentTime));} else {manager.seek(parseInt(e.progress * manager.duration / 100));}if (!manager.paused) {play(t);} else {pause(t);}}
}const changeAudioProgressBar = (e, t) => {//修改进度条等显示用的信息if (!(e.currentTime || e.progress || e.currentTime == 0 || e.progress == 0)) {console.log('没有参数,无法设置进度条');return;}let duration, durationTime, currentDuration, currentDurationTime, progress;duration = manager.duration;if (e.currentTime || e.currentTime == 0) {currentDuration = e.currentTime;progress = parseInt(100 * currentDuration / duration);} else {progress = e.progress;currentDuration = parseInt(progress * duration / 100);}let timeArr = [parseInt(duration / 60), parseInt(duration % 60), parseInt(currentDuration / 60), parseInt(currentDuration % 60)];for (let i in timeArr) {//小程序无法使用padstart,采用以下方式补全时间格式if (timeArr[i].toString().length == 1) {timeArr[i] = `0${timeArr[i]}`} else {timeArr[i] = `${timeArr[i]}`}}currentDurationTime = `${timeArr[2]}:${timeArr[3]}`;let backgroundAudio = t.data.backgroundAudio;backgroundAudio.currentDuration = currentDuration;backgroundAudio.currentDurationTime = currentDurationTime;backgroundAudio.progress = progress;t.setData({ backgroundAudio })return backgroundAudio;
}const play = (t) => {//播放if (resetAudio) {let e = {src: audioData.src,title: audioData.title,startTime: audioData.startTime}createAudio(e, t);}manager.play();if (t) {let backgroundAudio = t.data.backgroundAudio;backgroundAudio.isPlaying = true;t.setData({backgroundAudio})}
}
const pause = (t) => {//暂停manager.pause();if (t) {let backgroundAudio = t.data.backgroundAudio;backgroundAudio.isPlaying = false;t.setData({backgroundAudio})}
}
const stop = (t) => {//结束manager.stop();if (t) {let backgroundAudio = t.data.backgroundAudio;backgroundAudio.isPlaying = false;t.setData({backgroundAudio})}
}
const uninstall = (t) => {stop();//停止播放clearInterval(audioInterval);//清除计时器audioData = {//重置数据src: '',title: '',singer: '',epname: '',coverImgUrl: '',webUrl: ''};resetAudio = true;
}const setAudio = (e, t) => {//设置播放器数据if (!e.src) {alert('没有音频地址')return;}console.log('setAudio的信息');console.log(e);manager.src = e.src;manager.title = e.title;manager.startTime = e.startTime;manager.epname = e.epname || '';manager.singer = e.singer || '';manager.coverImgUrl = e.coverImgUrl || '';manager.webUrl = e.webUrl || '';//将音频数据暂存audioData.src = e.src;audioData.title = e.title;audioData.epname = e.epname || '';audioData.singer = e.singer || '';audioData.coverImgUrl = e.coverImgUrl || '';audioData.webUrl = e.webUrl || '';audioData.startTime = 0;resetAudio = false;pause(t);
}const hideAudio = (t) => {//切换到背景播放,暂时没用到}
const showAudio = (t) => {//切换到前台播放,暂时没用到if (!manager.currentTime || !manager.duration) {return;}
}const alert = (e) => {//提示wx.showToast({title: e,icon: 'none',mask: true})
}
module.exports = {init,getDuration,play,pause,stop,seek,hideAudio,showAudio,uninstall
}

index.js

//index.js
const app = getApp(), myAudio = require("../utils/audioManager.js");Page({data: {audio:{//用来存储服务器传输过来的内容src:'',title:'',coverImgUrl:''},backgroundAudio: {//实际正在播放的内容,必须配置在data中image: "",url: "",name: "",duration: "",durationTime: "",currentDuration: "",currentDurationTime: "",progress: "",isPlaying: false}},onLoad: function () {//模拟从服务器获取数据setTimeout(()=>{let audio={src:'http://rv01.sycdn.kuwo.cn/f79cf09a4426480dd5717af406275ffb/5d71f7df/resource/n3/2/9/591852463.mp3',title:'比翼的羽根',coverImgUrl:'https://goss.veer.com/creative/vcg/veer/800water/veer-146156021.jpg'};this.setData({audio})this.initBackGroundAudio();},2000);},//初始化音频initBackGroundAudio() {if (!this.data.audio.src) {return}let audio = {//设置播放器属性,src与title为必填src: this.data.audio.src,title: this.data.audio.title,coverImgUrl: this.data.audio.coverImgUrl};myAudio.init(audio, this);//初始化audiomyAudio.getDuration(audio, this);//获取视频长度myAudio.pause();//暂停播放},dragAudioSlider(e) {//拖动进度条myAudio.seek({progress: e.detail.value}, this)//跳转到该进度myAudio.play(this);//播放},//自定义音频播放器sliderChange(e) {myAudio.seek({progress: e.detail.value}, this)//跳转到该进度myAudio.play(this);//播放},//播放按钮playAudio() {if (this.data.backgroundAudio.isPlaying) {myAudio.pause(this);} else {myAudio.play(this);}},onUnload(){myAudio.uninstall(this);//卸载播放器,重置播放器数据}
})

index.wxml

<!-- index.wxml -->
<view class='audioPlayer'><view class='player'><image src='{{audio.coverImgUrl}}' class='audioBack' mode='aspectFill'></image><view class='audioControls'><view class='flex'><view class='bottom' catchtap='playAudio'><!-- 按钮 --><view wx:if="{{backgroundAudio.isPlaying}}"><image src='../images/pause.png' /></view><view wx:else><image src='../images/play.png' /></view></view><view class='slider'><slider bindchange='dragAudioSlider' activeColor='red' block-size="12" value='{{backgroundAudio.progress}}' /></view><view class='time'>{{backgroundAudio.currentDurationTime||'00:00'}}/{{backgroundAudio.durationTime||'00:00'}}</view></view></view></view>
</view>

index.wxss

/* index.wxss */
.flex{display: flex;
}
.audioPlayer{width: 100%;height: 400rpx;margin-bottom: 30rpx;box-sizing: border-box;padding: 20rpx 30rpx;
}
.player{width: 100%;height: 100%;position: relative;
}
.audioBack{width: 100%;height: 100%;
}
.audioControls{width: 100%;height: 80rpx;background: black;opacity: .8;position: absolute;bottom: 0;color: white;font-size: 6pt;line-height: 80rpx;text-align: center;
}
.audioControls .bottom{width: 60rpx;height: 100%;
}
.audioControls .bottom image{margin-top: 30%;margin-left: 30%;width: 40rpx;height: 40rpx;
}
.audioControls .slider{width: 520rpx;height: 100%;
}
.slider slider{width: 95%;margin-left: 4%;margin-right: 0;
}
.audioControls .time{width: 120rpx;height: 100%;
}

注意事项

1.使用时必须在使用的页面中引入audioManager.js,并且在data中设置好backgroundAudio的全部参数

2.必须要在页面onunload事件中卸载播放器,否则会导致interval一直存在占用内容,导致crash

3.需要在手机端预览,请填写appid

4.以下为播放暂停图片

微信小程序音频播放器(第二版)相关推荐

  1. 微信小程序音乐播放器

    趁周末做一个简单的微信小程序音乐播放器,源码已留. 播放列表首页wxml <swiper class="swiper" indicator-dots='{{swipterSe ...

  2. 微信小程序-音频播放-wx.createInnerAudioContext() 每次都是重复播放同一条录音

    前言 在调试微信小程序音频播放时,刚开始我也是直接复制官方文档的实例: const innerAudioContext = wx.createInnerAudioContext() innerAudi ...

  3. 微信小程序-音频播放 每次都是重复播放同一条录音

    前言 在调试微信小程序音频播放时,刚开始我也是直接复制官方文档的实例: const innerAudioContext = wx.createInnerAudioContext() innerAudi ...

  4. uniapp实现微信小程序音频播放倒计时的功能,类似微信语音条

    uniapp实现微信小程序音频播放功能 最近需要有个项目需要用到音频播放,第一个想到的是audio标签,但是查阅了uniapp官方文档,发现audio组件已经不维护了. 官网推荐使用uni.creat ...

  5. (附源码)springboot+基于微信小程序音乐播放器的设计与实现 毕业设计271156

    Springboot音乐播放小程序的设计与实现 摘 要 本文设计了一种基于微信小程序的音乐播放器,系统为人们提供了方便快捷.即用即搜的音乐搜索播放服务,包括音乐资讯.音乐库推荐.交流论坛.注册登录.最 ...

  6. 微信小程序-音乐播放器

    前言 本文主要通过微信小程序的媒体API来实现一个简单的音乐播放器,主要实现的功能有音乐的切换.单曲循环.播放进度条的拖拽.播放与暂停和自定义音乐列表弹窗功能. 效果图 主要目录文件 |--image ...

  7. springboot+基于微信小程序音乐播放器的设计与实现 毕业设计-附源码271156

    Springboot音乐播放小程序的设计与实现 摘 要 本文设计了一种基于微信小程序的音乐播放器,系统为人们提供了方便快捷.即用即搜的音乐搜索播放服务,包括音乐资讯.音乐库推荐.交流论坛.注册登录.最 ...

  8. 微信小程序——音乐播放器

    音乐播放器 前言 主页 三个标签页 推荐页 播放器页 播放列表页 逻辑 前言 使用swiper组件完成三个标签页的切换,并且实现轮播图.scroll-view组件完成滚动视图,使用微信小程序提供的音乐 ...

  9. 01. 微信小程序音乐播放器

    项目简介 最近在学微信小程序,所以打算做一个音乐播放器的微信小程序. 项目需求(原型图) 这个是我做的原型图,比较简陋(有些界面直接用了网易云音乐小程序的截图,因为是仿着网易云音乐来做的) 首页 播放 ...

  10. 计算机实战项目、毕业设计、课程设计之含论文+辩论PPT+源码等]微信小程序音乐播放器小程序+后台管理系统

    音乐播放器平台+后台管理系统|前后分离VUE>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序前台和Java做的后台管理系统,该后台采用前后台前后分离 ...

最新文章

  1. 单元测试Struts2的Action(包含源码)
  2. Popup窗口在XP+SP2下面受到限制
  3. java并发编程--Executor框架
  4. 容器处于restarting状态_Docker容器操作-基础命令
  5. 不同映射方式下cache的失效率_详解发动机在不同工况下的喷油量控制方式
  6. Spring MVC 3:上传多个文件
  7. 【JEECG技术文档】JEECG在线聊天插件功能集成文档
  8. js bom dom
  9. pytorch 中 torch.cat 函数的使用
  10. acs712电流检测怎么用_工程师都用这个巧妙廉价的电流检测电路!
  11. 第13周 本周个人总结
  12. Python基础--01
  13. isight2019安装教程_abaqus2019软件下载+安装教程
  14. 用Java实现md5加密
  15. 摄像头和机械臂的手眼标定
  16. 汽车CAN总线-基础
  17. PCB正片与负片之分以及实际使用建议
  18. pr导入srt字幕显示因文件头错误而不能打开,或pr导入字幕乱码
  19. win10系统下office2003和office2016兼容
  20. 2015-10-28 C#4

热门文章

  1. 【vscode简单入门(三)】vscode巨实用的基础插件推荐(不定期更新)
  2. 机器学习特征工程之特征缩放+无量纲化:非线性缩放(例如,sigmoid、tanh、arctan等)
  3. 网络编程中,同步传输和异步传输有什么区别
  4. linux之ls -l命令详解
  5. 实测 ubuntu20.04 机械式激光雷达与相机联合标定
  6. E4A 易安卓一些常见的小问题
  7. CAD批量打图精灵自动识别纸张大小
  8. EOS Error 3090003: provided keys, permissions, and delays do not satisfy declared authoriz
  9. Entity 连接数据库以及操作数据库
  10. python 有趣包_一些有趣且鲜为人知的 Python 特性