最近在写一个艾美食艾音乐的微信小程序,其中有用到音乐播放的功能,基本播放切换功能已经实现,但是在反复切换歌曲、重新进入歌曲以及单曲循环、列表循环的测试过程中还是发生了bug,特此写一篇文章,捋一下思路.(功能写到后面小程序官方文档将音频这一块全都更新了...)

  坑点:由于小程序主体部分没有app.wxml,这就导致小程序不能写一些公共的页面结构,如果有相同的部分,只能封装成组件再引入.

  在我们点击歌曲列表中的某首歌的时候,会进入音乐播放界面,当我们退出音乐播放界面,歌曲仍然继续播放,但此时由于退出当前路由,页面data中的数据也已被销毁,当我们再次进入播放界面相当于重新进行页面加载,所以需要我们进行分情况判断,播放歌曲变的较为复杂.

  一.存放公共数据

    在我们进入音乐播放界面之前要存一下:

      当前专辑信息:album(Object)

      当前播放列表:playList(Array)

      当前播放歌曲的index:playIndex(Number)

      播放模式:mode(String)

      封面旋转的角度:imgRotate(Number)

   

// app.js
globalData: {
album: null, // 当前专辑信息
playList: [], // 当前播放列表
playIndex: 0, // 当前播放歌曲index
mode: 'multiple', // 循环模式 multiple: 循环播放, single: 单曲循环
imgRotate: 0, // 封面旋转角度
}

  二.专辑列表

    在专辑列表中点击某个专辑,进入该专辑的歌曲列表,同时将 该专辑的信息 存入globalData.

// music.js
gotoSongList(e) {
let item = e.currentTarget.dataset.type
app.globalData.album = item // 将专辑信息存入globalData
wx.navigateTo({
url: '../songlist/songlist'
})
}

  三.歌曲列表

    在歌曲列表中点击播放某首歌时,进入歌曲播放界面,同时将 该专辑的歌曲列表、当前播放歌曲的index 存入globalData.

// songlist.js
// 播放歌曲
play(e) {
app.globalData.playList = this.data.songList
let index = e.currentTarget.dataset.index
app.globalData.playIndex = index
let url = '../player/player'
wx.navigateTo({
url: url
})
}

  四.歌曲播放页面

    需要在data中存放一下信息:

      当前歌曲信息:item(Object)

      歌曲解析后的歌词:parseLyric(String)

      当前播放进度点的歌词:lineLyric(String)

      播放模式:mode(String)

      封面旋转的角度:imgRotate(Number)

      进度条的值:SliderValue(Number)

      音频的长度:duration(Number)

      音频的播放位置:currentPosition(Number)

      播放状态:playStatus(Boolean)

const app = getApp();
var Base64 = require('../../utils/base64.js').Base64
var Lyric = require('../../utils/lyric-parse.js')
Page({
data: {
item: {}, // 当前歌曲信息
parseLyric: '', // 歌曲解析后的歌词
lineLyric: '', // 当前播放进度点的歌词
mode: '', // 播放模式
imgRotate: 0, // 封面旋转的角度
sliderValue: 0, // 进度条的值
duration: 0, // 音频的长度(单位:s)
currentPosition: 0, // 音频的播放位置(单位:s)
playStatus: 0, // 播放状态
timee: 0, // 定时器 根据歌曲进度改变slider进度
coverImg: '', // 封面图片
isDel: false, // 当前列表是否只有一首歌曲
},
onLoad() {
let item = app.globalData.playList[app.globalData.playIndex]
let album = app.globalData.album
// 获取背景音频信息
const backgroundAudioManager = wx.getBackgroundAudioManager()
console.log(backgroundAudioManager, 'backgroundAudioManager')
if (backgroundAudioManager.src == item.src) { // 继续听歌
console.log('继续听歌')
} else { // 播放新歌
app.globalData.imgRotate = 0
console.log('播放新歌')
backgroundAudioManager.title = item.name
backgroundAudioManager.epname = album.name
backgroundAudioManager.singer = item.author
backgroundAudioManager.coverImgUrl = album.poster
// 设置了 src 之后会自动播放
backgroundAudioManager.src = item.src
}
let lyric = Base64.decode(item.lyric)
this.setData({
item: item,
coverImg: album.poster,
playStatus: !backgroundAudioManager.paused,
duration: this.stotime(backgroundAudioManager.duration),
currentPosition: this.stotime(backgroundAudioManager.currentTime),
parseLyric: new Lyric(lyric, this.handleLyric),
mode: app.globalData.mode,
imgRotate: app.globalData.imgRotate
})
this.data.parseLyric.seek(backgroundAudioManager.currentTime*1000)
console.log(this.data.playStatus, 'playStatus')
if (backgroundAudioManager.paused) {
this.data.parseLyric.togglePlay()
} else if (!this.data.timee) {
this.toRotate()
}
backgroundAudioManager.onPlay(this.onPlay) // 监听背景音频播放事件
backgroundAudioManager.onPause(this.onPause) // 监听背景音频暂停事件
backgroundAudioManager.onTimeUpdate(this.onTimeUpdate) // 监听背景音频播放进度更新事件
backgroundAudioManager.onEnded(this.onEnded) // 监听背景音频自然播放结束事件
wx.setNavigationBarTitle({
title: item.name
})
console.log(app.globalData.playList.length, 'app.globalData.playList.length')
if (app.globalData.playList.length == 1) {
this.setData({
isDel: true
})
}
},
handleLyric({lineNum, txt}) { // 歌词回调
console.log(lineNum, txt, 'txt')
this.setData({
lineLyric: txt
})
},
onPlay() {
const backgroundAudioManager = wx.getBackgroundAudioManager()
console.log('onPlay')
console.log(backgroundAudioManager.duration, 'backgroundAudioManager.duration')
this.setData({
playStatus: true
})
this.data.parseLyric.seek(backgroundAudioManager.currentTime*1000)
this.toRotate()
},
onPause() {
clearInterval(this.data.timee)
this.data.parseLyric.stop()
console.log('onPause')
this.setData({
playStatus: false
})
},
switch() { // 切换歌曲播放状态
if (this.data.playStatus) { // 切换为暂停状态
const backgroundAudioManager = wx.getBackgroundAudioManager()
backgroundAudioManager.pause()
} else { // 切换为播放状态
const backgroundAudioManager = wx.getBackgroundAudioManager()
backgroundAudioManager.play()
}
},
onTimeUpdate() {
const backgroundAudioManager = wx.getBackgroundAudioManager()
let sliderValue = backgroundAudioManager.currentTime / backgroundAudioManager.duration * 100
this.setData({
currentPosition: this.stotime(backgroundAudioManager.currentTime),
sliderValue: sliderValue,
duration: this.stotime(backgroundAudioManager.duration)
})
// this.data.parseLyric.seek(backgroundAudioManager.currentTime*1000)
},
toRotate() {
this.data.timee && clearInterval(this.data.timee)
this.data.timee = setInterval(() => {
app.globalData.imgRotate = app.globalData.imgRotate + 0.8
this.setData({
imgRotate: app.globalData.imgRotate
})
}, 35)
},
onEnded() {
console.log('onEnded')
this.setData({
playStatus: false
})
if (this.data.mode == 'multiple') {
this.cutNext()
} else {
const backgroundAudioManager = wx.getBackgroundAudioManager()
// 设置了 src 之后会自动播放
backgroundAudioManager.src = this.data.item.src
}
},
slideChange(e) { // 拖动滑块
let value = e.detail.value
this.setData({
sliderValue: value
})
const backgroundAudioManager = wx.getBackgroundAudioManager()
let currentTime = (value / 100) * backgroundAudioManager.duration
backgroundAudioManager.seek(currentTime)
this.data.parseLyric.seek(currentTime*1000)
},
cutPrev() { // 上一首
this.delSongChange('prev')
},
cutNext() { // 下一首
this.delSongChange('next')
},
delSongChange(type) { // 切换歌曲
if (this.data.duration !== 0 && !this.data.isDel) {
if (app.globalData.playList.length > 1) {
clearInterval(this.data.timee)
}
this.data.duration = 0
this.data.parseLyric.stop()
if (type == 'prev') {
if (app.globalData.playIndex > 0) {
app.globalData.playIndex --
} else {
app.globalData.playIndex = app.globalData.playList.length - 1
}
} else {
if (app.globalData.playIndex < app.globalData.playList.length - 1) {
app.globalData.playIndex ++
} else {
app.globalData.playIndex = 0
}
}
let item = app.globalData.playList[app.globalData.playIndex]
wx.setNavigationBarTitle({
title: item.name
})
const backgroundAudioManager = wx.getBackgroundAudioManager()
backgroundAudioManager.title = item.name
backgroundAudioManager.singer = item.author
// 设置了 src 之后会自动播放
backgroundAudioManager.src = item.src
let lyric = Base64.decode(item.lyric)
this.setData({
item: item,
playStatus: !backgroundAudioManager.paused,
parseLyric: new Lyric(lyric, this.handleLyric)
})
this.data.parseLyric.seek(backgroundAudioManager.currentTime*1000)
console.log(this.data.playStatus, 'playStatus')
if (backgroundAudioManager.paused) {
this.data.parseLyric.togglePlay()
}
}
},
// 改变播放模式
changeMode() {
if (this.data.mode == 'multiple') {
this.setData({
mode: 'single'
})
} else {
this.setData({
mode: 'multiple'
})
}
app.globalData.mode = this.data.mode
},
// 时间格式转换
stotime(s) {
let t = ''
if (s > -1) {
let min = Math.floor(s / 60) % 60;
let sec = Math.floor(s) % 60
if (min < 10) { t += '0' }
t += min + ':'
if (sec < 10) { t += '0' }
t += sec
}
return t
},
onUnload() { // 页面卸载
const backgroundAudioManager = wx.getBackgroundAudioManager()
backgroundAudioManager.onTimeUpdate()
backgroundAudioManager.onPlay()
backgroundAudioManager.onPause()
this.data.parseLyric.stop()
clearInterval(this.data.timee)
},
})

微信小程序音乐播放的更多相关文章

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

    写在前面 1.入门几天小白的作品,希望为您有帮助,有好的意见或简易烦请赐教 2.微信小程序审核音乐类别已经下架,想要发布选题需慎重.附一个参考链接,感谢https://www.hishop.com.c ...

  2. 微信小程序音乐播放器组件

    wxml <image bindtap="click" src="{{isPlay?'/images/':'/images/'}}"/> JS Pa ...

  3. 微信小程序---音乐播放和控制

    1.效果图如下: 2.代码如下: //index.js //获取应用实例 var app = getApp() Page({ data: { motto: 'Hello World', userInf ...

  4. 微信小程序音频播放 InnerAudioContext 的用法

    今天项目上涉及到了微信小程序播放音频功能,所以今天跟着一些教程做了个简单的播放器 1.实现思路 刚开始想着有没有现成的组件可以直接用,找到了微信的媒体组件 audio,奈何看着 1.6.0版本开始,该 ...

  5. 微信小程序——音频播放器

    先来个效果图韵下味: 需求: 音频的播放,暂停,中间按钮状态的变化,播放时实时更新播放进度: 前进15s,后退15s: 进度条拖动. 一开始想着这3个功能应该挺简单的.不就是播放,暂停,前进,后退么~ ...

  6. 微信小程序 - 音频播放(1.2版本和1.2版本之后)

    不多说了,直接贴code // 1.2版本以后便不在维护 wx.getBackgroundAudioManager({ success:function(res){ var status =res.s ...

  7. 微信小程序实例源码大全

    微信小程序实例源码大全下载 微信小应用示例代码(phodal/weapp-quick)源码链接:https://github.com/phodal/weapp-quick 微信小应用地图定位demo( ...

  8. 微信小程序源码推荐

    wx-gesture-lock  微信小程序的手势密码 WXCustomSwitch 微信小程序自定义 Switch 组件模板 WeixinAppBdNovel 微信小程序demo:百度小说搜索 sh ...

  9. 近期热门微信小程序demo源码下载汇总

    近期微信小程序demo源码下载汇总,乃小程序学习分析必备素材!点击标题即可下载: 即速应用首发!原创!电商商场Demo 优质微信小程序推荐 -秀人美女图 图片下载.滑动翻页 微信小程序 - 新词 GE ...

随机推荐

  1. [翻译 EF Core in Action] 1.5 关于NoSql

    Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...

  2. k8s滚动更新(六)--技术流ken

    实践 滚动更新是一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新.滚动更新的最大的好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性. 下面我们部署三副本应用, ...

  3. C#连接基于Java开发IM——Openfire

    Openfire简介    Openfire 是开源的.基于可拓展通讯和表示协议(XMPP).采用Java编程语言开发的实时协作服务器.Openfire的效率很高,单台服务器可支持上万并发用户.    ...

  4. [TCP/IP] 数据链路层-ethereal 抓包分析数据帧

    1.下载 http://dx1.pc0359.cn/soft/e/ethereal.rar 2.打开软件,指定抓取的网卡,下面是我抓取自己的主要网卡数据 3.开启个ping命令 , 不停的ping一台 ...

  5. git status 显示中文乱码

    场景 在使用git命令行查看当前 状态时, git status 显示中文文件乱码:  解决 修改git配置, git config --global core.quotepath false

  6. 一个GIS开源工具集架构的总结

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 最近由团队HWG主导的GIS开源工具集基本告一段落,该项目虽然 ...

  7. 谈谈git以及如何关联github

    git :一款免费.开源的分布式代码版本管理控制系统 记录当前产品代码的所有版本信息,包括历史修改信息 方便快速回退到某一个具体的版本 方便团队协作开发 可检测代码冲突.合并代码等 1.利用 git ...

  8. JDBC获取数据库连接

    是什么? JDBC:Java Data Base Connectivity(java数据库连接) 为什么用? sun公司提供JDBC API接口,数据库厂商来提供实现 我们需要用哪个数据库就加载那个数 ...

  9. Gitlab管理网页老是500错误?增加物理内存,增加cpu吧

    上一篇 CentOS 7 系统下 GitLab 搭建 搭建时,是用的是1G内存, 访问gitlab管理网页非常慢,常常出现 500错误 查询后发现: Gitlab的运行对CPU是有要求的:2核心 支持 ...

  10. WEB框架-Django框架学习(一)-基础层级关系

    今日主要内容为Django架构,主要有路由层,视图层和模板层 1. Django的路由层 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之 ...