最近在写一个艾美食艾音乐的微信小程序,其中有用到音乐播放的功能,基本播放切换功能已经实现,但是在反复切换歌曲、重新进入歌曲以及单曲循环、列表循环的测试过程中还是发生了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. 手撸GitLab CI(阉割版)

    上一集我们说到如何从零开始搭建一个Vue-cli 3.0的项目,而这一集我们将说到如何手写一份阉割版的CI脚本. 首先说一下GitLab部署到服务器的操作,一般有两种,一种是规范化分离的,包含runn ...

  2. 挖一挖@Bean这个东西

    有Bean得治 任何一个正常程序的访问都会在内存中创建非常多的对象,对象与对象之间还会出现很多依赖关系(一个处理业务逻辑的类中几乎都会使用到别的类的实例),一般的做法都是使用new关键字来创建对象,对 ...

  3. SpringBoot技术栈搭建个人博客【前台开发/项目总结】

    前言:写前台真的是我不擅长的东西...所以学习和写了很久很久...前台页面大概开发了两天半就开发好了,采用的静态的html和bootstrap来写,写后台的时候纠结住了...怎么说呢,写页面真的是头疼 ...

  4. 【Java】几道让你拿offer的知识点

    前言 只有光头才能变强 之前在刷博客的时候,发现一些写得比较好的博客都会默默收藏起来.最近在查阅补漏,有的知识点比较重要的,但是在之前的博客中还没有写到,于是趁着闲整理一下. 文本的知识点: Inte ...

  5. (二)surging 微服务框架使用系列之surging 的准备工作consul安装

    suging 的注册中心支持consul跟zookeeper.因为consul跟zookeeper的配置都差不多,所以只是consul的配置 consul下载地址:https://www.consul ...

  6. SpringCloud系列——Config 配置中心

    前言 Spring Cloud Config为分布式系统中的外部化配置提供了服务器端和客户端支持.有了配置服务器,您就有了一个中心位置来管理跨所有环境的应用程序的外部属性.本文记录实现一个配置中心.客 ...

  7. 第一册:lesson 113.

    原文:Small changes. question:Who has got some small changes? Fares,please! Trafalgar Square,please. I' ...

  8. 零基础学Python--------第9章 异常处理及程序调试

    第9章 异常处理及程序调试 9.1 异常概述 在程序运行过程中,经常会遇到各种各样的错误,这些错误统称为“异常”.这些异常有的是由于开发者将关键字敲错导致的,这类错误多数产生的是SyntaxError ...

  9. 04 入门 - ASP.NET MVC应用程序的结构

    目录索引:<ASP.NET MVC 5 高级编程>学习笔记 用Visual Studio创建了一个新的ASP.NET MVC应用程序后,将自动向这个项目中添加一些文件和目录. 如图所示: ...

  10. 纯CSS编写汉克狗

    1,CSS中原生的变量定义语法是:--*,变量使用语法是:var(--*),其中*表示我们的变量名称:在CSS变量命名中,不能包含$,[,^,(,%等字符,普通字符局限在只要是“数字[0-9]”“字母 ...