为了提高自己,最近在学习微信小程序,选题是仿网易云音乐。期间踩过了大把的坑,bug出现的难受和解决bug欢喜,一直是伴随我阶段性学习这个项目的心情。初步完成了项目的主要功能,来分享一下自己的心路历程。
实现功能
- 列表式渲染数据
- 图片轮播
- 传参页面跳转
- 按钮点击弹窗
- 音乐播放、暂停、上一曲、下一曲
- 选歌播放
- 嵌套template页及传递数据
项目展示
- 首屏
(图一)
- 页面的切换
(图二)
- 播放效果
(图三)
- 暂停、上一首、下一首
(图四)
- 弹窗及选歌
(图五)
项目实现
项目思想
*
小程序的开发模式是MVVM模式。简单的讲就是页面绑定的值改变,页面就发生改变;页面改变,页面的绑定的值改变。这样的话,列表式渲染就十分好用。只用写一个通用的骨架,然后使用列表渲染生成页面,这样非常省时间省力气。所以这个项目,大量充斥着列表渲染。
有的页面部分可能会出现在好几个页面上。在这个项目里,页面顶部的部分出现在多个部分中,同时小程序里很多地方需要用到**弹性布局居中效果**于是我便把常用css样式写在app.wxss中,这样可以复用。
页面右上角的四根竖线出现在多个页面中,那变可以单独拿出来写,然后在通过template,导入至不同的页面中去。
选歌很需要解决的一点就是怎么才知道选择的是哪一首歌,歌单是哪一个歌单。一个页面获取到其他页面想传递过来的数据的方式有很多。其一、可以通过url跳转的时候,传参跳转,再通过跳转页面中onload事件添加options参数获得。其二、可以通过点击事件改变全局属性globalData的某项的值,然后再跳转页面中得到globalData中相应的值,便能知道页面跳转中想传递的值。这个项目使用了这两种方式,url传参获取播放第几首歌曲,全局属性globalData传递歌单。
项目资源
- 后台数据使用的是Easy Mock假数据,一个方便的数据构建平台。
当然还有方便的weui框架了,这个框架可以去github上拷贝,然后再根据weui示例,找到想要的想过,再去下载好了的文件里找到对应的代码,试一试便知道要如何使用了。
图片和音乐的话,因为使用的是网络地址。如果直接从网站上,按F12找到资源然后提取的话,通常提取的资源过几天便会失效。所以我们需要百度音乐外链、图片外链,然后会有相应的网站,可以生成一个长期不失效的链接,供我们下载图片和音乐。
踩过的坑与爬坑路
坑爹的图片问题:
- 项目起步第一个问题便是图片存放与加载。一些需要推送的消息以图片的形式展示,那么这个图是千万不能存在本地,需要通过src链接网络地址然后下载显示。那么问题来了:首页结构已经出来,图片却要延迟出来。页面则会出现这种情况:
- 经过思考,发现首页图片轮播条有很多张图片,他们会同时加载。而需求最急的是显示好第一张图片,第一张图片加载完成后,再加载其他图片。这样能减少页面首加载中,图片加载的将近一半的网速占用。查文档发现,小程序中图片加载完成后,有一个加载完成事件
bindload
。
因为使用的是列表渲染来填充页面,所以便可以让绑定渲染图片的数据showImage起始为空,这样页面就先不会渲染,然后第一张图加载完后,再给showImage赋值,然后就会自动渲染页面,加载其他图片了。这样就能提高页面的加载速度。
(备注:这里有些像懒加载的味道,在用户需要的时候加载图片)
这里有一个小小的技巧,第一张图的swiper-item不参与页面渲染,这样第一张图就一定会进行加载。在第一张图加载完成后,再进行页面渲染。同时让swiper开始轮播效果和生成指示点。
播放页面动画和还原
- 音频的后台播放
在播放界面时,一开始使用的<audio>
组件,洋洋洒洒敲下了一连串的代码,播放音乐,一切正常。但当我们前往另一个页面时,播放的音乐就没声音了。查了文档才知道audio
并不能实现后台播放,实现后台播放的是wx.getBackgroundAudioPlayerState()
和wx.getBackgroundAudioManager()
两个api。前者在微信客户端1.2.0版本就不开始维护了,后者低版本需做兼容处理。这个项目我使用的是第二个api。
(备注:wx.getBackgroundAudioManager()官方文档)
值得注意的是,当音频对象的src取得链接时,就自动开始播放。
- 播放状态。
歌曲播放时页面动起来,歌曲未播放时静止
看见动画了,第一个反应是css的animation,后来经过思考,如果不进行dom操作就要控制动画的进行与否需要做的数据绑定就会很多,不方便使用。于是查文档发现`wx.createAnimation(OBJECT)`这个api,但使用这个api,如果需要做到动画的循环播放,要写的js也很多很麻烦。经过了各种踩坑,根据小程序中的`progress`进度条组件,发现一个很棒的方法,那就是行内样式绑定数据。
(备注:指针动画简单,进行一次就结束,这里不提。。)
(备注:进度条是小程序自带的组件,已播放时间完成方式和进度条相似,这里与动画效果一并提出)
这样,只用在播放时,设计计时器,定时的按比列更改rotata、left、progress、的值,页面就会有相关改变。这个函数中,一开始便是清除计时器,因为有一个坑点:点击下一曲或上一曲时,计时器并未清除,那么,便会有两个计时器同时作用于一个值得改变(这种头疼的情况相信很多人都遇到过)。把三个计时器(转盘、按钮、进度条)在函数运行的开始就做清除,这样就让每次调用函数时,都先清除上一层的计时器,做到只有一个计时器作用于一个值。这种方式,用少量的代码,形成了可控的动画效果,很是方便。
(我在这收获了另一种写动画效果的方式,哈哈)
next: function () {
// 全局定义了proSet rotSet timeSet,因为需要清除计时器
var timeCount;
clearInterval(proSet);
clearInterval(rotSet);
clearInterval(timeSet);
proSet = setInterval(() => {
if (this.data.progress >= 100) {
i++;
if(i==this.data.music.length){
i=0;
}
app.globalData.i=i;
backgroundAudioManager.stop();
this.nameBackMusic();
timeCount = 0;
this.setData({
progress: 0,
left: 0,
songTime: this.data.music[i].songTime,
songer: this.data.music[i].songer,
songName: this.data.music[i].songName,
time: secondToDate(this.data.music[i].songTime)
});
}
else if (this.data.run == 0) {
clearInterval(proSet);
clearInterval(rotSet);
clearInterval(timeSet);
}
this.setData({
progress: 0.01 + this.data.progress,
left: 0.0458 + this.data.left
});
}, this.data.music[i].songTime / 10);
rotSet = setInterval(() => {
this.setData({
rotate: 1 + this.data.rotate,
});
}, 24);
timeCount = backgroundAudioManager.currentTime;
if (typeof (backgroundAudioManager.currentTime) === "undefined")
{
timeCount = 0;
}
timeSet = setInterval(()=>{
timeCount++;
this.setData({
currentTime: secondToDate(timeCount),
//secondToDate用来把n秒转换为xx:xx的显示形式
});
},1000)
}
- 页面还原
在播放界面中,设计一个值run
初始值为0,用来记录是否播放,播放时run为1,暂停时run为0。在页面跳转在返回播放页面时,之前因为播放设置的data值会全部还原,导致页面静态显示(进度条不动、时间不增加等)。这个时候,全局属性globalData就上场了。不论是在选歌、播放、暂停的时候,globalData中的变量记录播放的状态(是否播放、播放哪一首歌等)。而播放页面重新打开会执行onShow()
生命周期函数,这个时候变可以从全局变量中得到播放的状态,然后决定播放页面是否要动起来和相应的数据)。
因为页面第一次加载也会执行onShow()
函数,而暂停音乐时backgroundAudioManager.paused
返回true,播放时放回fals,没有音乐播放时返回undefined,如果单纯的用:if(backgroundAudioManager.paused)
则会判断无音乐和音乐播放时都为假,这样两种不同的情况执行相同的操作,则会发生意外,所以需要添加这样的判断if (typeof (backgroundAudioManager.paused) !== "undefined")
用以区分播放和无音乐事件。
结语
一路学习过来,期间碰到的大大小小的问题数不胜数,收获很大。目前还有一些功能暂未实现,会在以后继续完善项目,继续学习。
这个项目给我最大的启示就是文档是一个好东西,锻炼看文档的能力会自己接受新东西的速度变快。再就是很多时候解决问题的方法多种多样,写代码时可以多做几次考虑用哪种方式实现一个功能,这样既让项目变得更高校,也让自己变得更优秀。
个人邮箱:QiuShuiZC@163.com
github地址:秋水白
wx: zcfusheng
大家可以一起交流学习,如果觉得这个项目不错的话,用star来砸我吧。
(备注:我给项目里放的音乐都是周董和姿妈的,哈哈,毕竟男杰伦,女燕姿)