博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
指尖一点歌声来--微信小程序之仿网易云音乐心得
阅读量:6305 次
发布时间:2019-06-22

本文共 4912 字,大约阅读时间需要 16 分钟。

为了提高自己,最近在学习微信小程序,选题是仿网易云音乐。期间踩过了大把的坑,bug出现的难受和解决bug欢喜,一直是伴随我阶段性学习这个项目的心情。初步完成了项目的主要功能,来分享一下自己的心路历程。

实现功能

  • 列表式渲染数据
  • 图片轮播
  • 传参页面跳转
  • 按钮点击弹窗
  • 音乐播放、暂停、上一曲、下一曲
  • 选歌播放
  • 嵌套template页及传递数据

项目展示

  • 首屏

(图一)

  • 页面的切换

(图二)

  • 播放效果

(图三)

  • 暂停、上一首、下一首

(图四)

  • 弹窗及选歌

(图五)

项目实现

项目思想

*

小程序的开发模式是MVVM模式。简单的讲就是页面绑定的值改变,页面就发生改变;页面改变,页面的绑定的值改变。这样的话,列表式渲染就十分好用。只用写一个通用的骨架,然后使用列表渲染生成页面,这样非常省时间省力气。所以这个项目,大量充斥着列表渲染。有的页面部分可能会出现在好几个页面上。在这个项目里,页面顶部的部分出现在多个部分中,同时小程序里很多地方需要用到**弹性布局居中效果**于是我便把常用css样式写在app.wxss中,这样可以复用。页面右上角的四根竖线出现在多个页面中,那变可以单独拿出来写,然后在通过template,导入至不同的页面中去。选歌很需要解决的一点就是怎么才知道选择的是哪一首歌,歌单是哪一个歌单。一个页面获取到其他页面想传递过来的数据的方式有很多。其一、可以通过url跳转的时候,传参跳转,再通过跳转页面中onload事件添加options参数获得。其二、可以通过点击事件改变全局属性globalData的某项的值,然后再跳转页面中得到globalData中相应的值,便能知道页面跳转中想传递的值。这个项目使用了这两种方式,url传参获取播放第几首歌曲,全局属性globalData传递歌单。

项目资源

  • 后台数据使用的是假数据,一个方便的数据构建平台。
    当然还有方便的weui框架了,这个框架可以去github上拷贝,然后再根据weui示例,找到想要的想过,再去下载好了的文件里找到对应的代码,试一试便知道要如何使用了。
    图片和音乐的话,因为使用的是网络地址。如果直接从网站上,按F12找到资源然后提取的话,通常提取的资源过几天便会失效。所以我们需要百度音乐外链、图片外链,然后会有相应的网站,可以生成一个长期不失效的链接,供我们下载图片和音乐。

踩过的坑与爬坑路

坑爹的图片问题:

  • 项目起步第一个问题便是图片存放与加载。一些需要推送的消息以图片的形式展示,那么这个图是千万不能存在本地,需要通过src链接网络地址然后下载显示。那么问题来了:首页结构已经出来,图片却要延迟出来。页面则会出现这种情况:

  • 经过思考,发现首页图片轮播条有很多张图片,他们会同时加载。而需求最急的是显示好第一张图片,第一张图片加载完成后,再加载其他图片。这样能减少页面首加载中,图片加载的将近一半的网速占用。查文档发现,小程序中图片加载完成后,有一个加载完成事件bindload
    因为使用的是列表渲染来填充页面,所以便可以让绑定渲染图片的数据showImage起始为空,这样页面就先不会渲染,然后第一张图加载完后,再给showImage赋值,然后就会自动渲染页面,加载其他图片了。这样就能提高页面的加载速度。
    (备注:这里有些像懒加载的味道,在用户需要的时候加载图片)

这里有一个小小的技巧,第一张图的swiper-item不参与页面渲染,这样第一张图就一定会进行加载。在第一张图加载完成后,再进行页面渲染。同时让swiper开始轮播效果和生成指示点。

播放页面动画和还原

  • 音频的后台播放

在播放界面时,一开始使用的<audio>组件,洋洋洒洒敲下了一连串的代码,播放音乐,一切正常。但当我们前往另一个页面时,播放的音乐就没声音了。查了文档才知道audio并不能实现后台播放,实现后台播放的是wx.getBackgroundAudioPlayerState()wx.getBackgroundAudioManager()两个api。前者在微信客户端1.2.0版本就不开始维护了,后者低版本需做兼容处理。这个项目我使用的是第二个api。

(备注:)
值得注意的是,当音频对象的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来砸我吧。

(备注:我给项目里放的音乐都是周董和姿妈的,哈哈,毕竟男杰伦,女燕姿)

转载地址:http://uoixa.baihongyu.com/

你可能感兴趣的文章
sessionKey
查看>>
高性能Javascript--脚本的无阻塞加载策略
查看>>
Java 编程的动态性, 第4部分: 用 Javassist 进行类转换--转载
查看>>
完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三
查看>>
iOS8 Push Notifications
查看>>
各大名企笔试及面经大全(程序猿必读)
查看>>
Oracle 连接、会话数的查看,修改
查看>>
Python使用QRCode模块生成二维码
查看>>
英语学习的重要性
查看>>
Android中Handler引起的内存泄露
查看>>
原产地政策,jsonp跨域
查看>>
HDU 1143 Tri Tiling(递归)
查看>>
ffmpeg参数具体解释
查看>>
记一次公司仓库数据库服务器死锁过程
查看>>
Oracle 11g password过期被锁定报道 ORA-28000 the account is locked
查看>>
【Struts2学习笔记(2)】Action默认值和配置Action于result各种转发类型
查看>>
轨磁条简介
查看>>
(算法)交错的字符串
查看>>
hdu 5471(状压DP or 容斥)
查看>>
oracle.jdbc.driver.OracleDriver和oracle.jdbc.OracleDriver这两个驱动的区别
查看>>