我是一个大二的学生,在接触小程序之前我是一个学计算机运维的,后来入了坑,在入坑以后开发了两个小程序。
第一个是为学校开发的一个考勤的小程序,样式是别人设计的,后台是用老师帮忙写的,用PHP和MySQL写的,当时我还不懂怎么写后台接口,我主要是实现了小程序的一些功能,直到现在,我都还是一直在维护这个小程序,在一些功能上的升级什么的,由于学校学生的数量多,数据量大,所以在数据处理上花了不少的功夫,这里就不多说了。
第二个是为了参加全国高校小程序大赛写的一个小程序,虽然这个我并没有花多少心思,但是这个全权为我一个人负责写的,虽然样式还是请的专业ui设计人员设计的。我花学生价在阿里云上买了一个云服务器,自己搭建的Apache,PHP,MySQL,然后自己写的接口,但时没有备案的域名,所以这个小程序只能算一个试验品。
开发了两个项目之后我回头看看我当初是怎么入这个坑的,找到了我当时写的一份豆瓣电影小程序解析的文档,发现我现在写代码的风格完全和豆瓣电影小程序代码风格一样。下面我是处入坑解析的文档,有错误的地方欢迎指出了。
电影程序解析过程
一、电影的主页加载过程和下拉刷新和下拉触底的实现
首先我解析程序是按照程序的执行流程进行解析的,开始程序加载的是pages/popular/popular这个页面,从popular.wxml开始看起
该页面分为3块,第一块是搜索框加轮播,第二块和第三块是引用的两个模板文件。首先第一行代码有一个if判断,在js中看到该值为true,所以这里取反为false。所以该处的代码先放着。
看引入的一块模板
这里最外面有一个if判断,该值为true,所以加载里面的内容,这里class=“loading”是全局的,所以再进app.wxss中看,
这里用的固定定位,然后设置居屏幕中间,设置宽高为200rpx,所以图片整体往右下移动了200rpx,所以又设置margin为-100rpx移动,这样图像就是居中的,然后设置文字行高为300rpx,(其实这个300rpx是图片高度,150rpx)然后设置圆角,然后引入背景图片等等,最下面的animation:bounceIn .3s这里是css3的动画效果,执行一次该动画有时0.3s,关于css3更多动画http://css3lib.alloyteam.com/uilib/animation/demo1/#cta。
*引入的第二块模板先不看。*
接下来看popular.js。
首先看到引用了外部的两个js模块,然后page里面data定义了初始值,然后是页面的渲染,执行onLoad函数,执行第14行代码,在导航条显示加载动画,然后执行app.getCity函数,第三行代码有引入getApp,在执行该函数的时候把函数作为实参传递进去,函数为第15行到第25行,然后看app.js。此时导航条的加载动画还在执行。
该函数的形参以cb接收,这里注意var that=this,然后执行微信自带的API接口wx.getLocation接收用户的地理位置,返回的类型为gcj02,返回的将会是经纬度,然后当获取数据成功时,把维度和经度进行拼串处理,(中间加个逗号,经度加1)然后做一个网络请求,把用户的经纬度在百度地图上换算成地址,第33行URL接口是从引入的js中获取的百度地图接口,data中传入了几行数据,ak是密钥,location是刚刚获取的经纬度,output获取数据格式类型,pois不懂是什么,然后是获取数据的方法,然后当数据请求成功时,返回res,res.data.result.addressComponent.city是返回的所在的城市地址,城市地址给config.city,然后用slice进行字符串的截取,0为初始位置,-1是倒数一位数,(例如:我所在的地方是武汉市,截取出来就是武汉),然后判断cb是否为函数,是函数就执行这个函数,并把城市位置作为实参传递进去,(这里我认为没必要这么写,这里cb已经写好了为函数,所以我觉得没必要判断,并且把地址传递进去也没什么用,这个函数里面用的是config.city。所以可以直接执行cb()就好了。)如果失败就重新执行这个函数,这里突显了var that=this的意义,如果上面不写这行代码,这里写this.getCity(),那么这里的this就不是指代整个app.js了,就达不到我们想要的效果。
到这里为止我们获取到了城市信息,上导航条加载完成。然后接着回popular.js看正在执行的函数,当该函数开始执行,第16条代码隐藏导航条加载动画,17行代码设置当前标题,然后执行20条代码。
第20行代码是执行douban.fetchFilms,在this中执行,这是call的用法。(
//call方法的意思是把douban.fetchFilms方法放到that上执行
//douban.fetchFilms中的this指向的是that,也就是这个页面的函数,
//call传递的参数是以字符串形式,apply是以数组形式传递,仅此区别
//这一段代码的作用是让douban.fetchFilms方法在that中执行。
)传递进去两个参数,一个为豆瓣的接口,一个为刚刚赋的初始值,也就是电影数量start,然后接着看douban.fetchFilms。
首先依然是引入了两个js模板,在第7行代码时候调用了message.hide,同样是用的call方法,在当前页面调用,然后找到message.hide
这里的hide实现的功能是把visiable设为false,这里回到看刚刚主页没有看的第二块模板。
这里的hidden是隐藏元素的用法,这里message.visiable刚刚得到是false,所以这里是true,所以这里的元素被隐藏了,其实这里隐藏的元素是没有网络下的样式,然后返回看douban.fetchFilms,下面是if判断that.data.hasMore,初始值hasMore为true,然后调用的是网络请求,URL是豆瓣接口,然后data传入的当前城市,当前电影数量,和总数(config.count),然后下面是传输类型,和编码样式,当网络请求成功时,里面做了一个if判断,判断获得的电影数是否为0,如果为0的话,说明该地区没有电影,就设置hasMore为false,否则就把电影详情给films,that.data.films.concat(res.data.subjects),这里的concat是连接两个或多个数组用的,例如,films中原本就有一些电影详情,就会把获取的电影和原本的电影拼成一个数组。然后是电影数量start,也是原来的电影数量加新加的电影数量,并且showLoading设置为false,然后回头看引入的第一块模板,正在加载动画就没了,主页的搜索框和轮播图会出来,下面的电影页面也会会加载出来,下面有页面下拉刷新和网络请求失败的函数,因为之前有提过,这里就不细讲了,搜索框有一个box-shadow: 0 10rpx 60rpx rgba(0, 0, 0, .3);css样式,这个是阴影,第一个值是阴影右移的距离,第二个值是阴影下移的距离,可以为负值,后面是颜色和透明度。
然后回到popular.js。下面有一个下拉刷新的函数和一个上拉触底函数,下拉刷新就是把变量初始化,然后重新执行一遍onLoad函数,上导航条的城市地址也会重新加载,但是下拉触底只是执行了douban.fetchFilms.call(that, config.apiList.popular, that.data.start)然后再获取电影信息,在上传的三个变量,城市,当前电影数,和每次获取电影的总数,第一次上传的当前电影数(start)为0,第二次上传的为第一次获取电影总数,所以传过来的电影数为0,(经过测试,如果当前地区的电影为15,如果上传的电影数为10,就会返回最新的5部电影,这也就是为什么第二次获取的电影为0),然后设置hasMore为false,然后主页最下面的“拼命加载中...”会变成“没有更多内容了”,到这里为止主页的加载、下拉刷新和上拉触底全部分析完了。
二、电影详情页面和电影的类型页面
在filmList.wxml页面中有为每个页面绑定一个id,从获取到的电影详情里面的id进行赋值,还绑定了一个catchtap,同时在电影页面也为电影的类型做了一个for循环,(因为不确定一部电影有几种类型),同时给每个类型绑定了一个tag属性和catchtap单击响应事件。
点击单个电影后跳转到filmDetail页面并传入其id,然后看filmDetail.wxml会执行一个正在加载的动画,因为filmDetail.js中的showLoading为true。
看这个js。首先声明一个id用来接收传过来的id,然后在当前位置执行douban.fetchFilmDetail,传入电影详情接口和id和一个函数,获取过程和获取电影信息是一样,这里不细讲,然后执行后面异步获取数据的api,(关于异步获取数据和同步获取数据的区别不太了解),从key=film_favorite中获取数据,并用遍历判断这个电影数据是否和当前浏览的电影数据是否相同。如果相同就设置isFilmFavorite为true,也就是已经收藏过。
首先声明三个变量,一个当前日期,一个当前时间,一个空数组,然后异步获取数据,当获取数据成功时,把该数据存到那个空数组中,然后获取当前时间和当前浏览的电影数据存入到now_data对象中,获取当前日期和一个空数组存入到sub_data对象中,然后将这个now_data对象存入sub_data的films数组中,(push方法可以向数组末尾添加一个或多个元素,并返回新的长度),然后判断这里的film_history是否为空,(也就是查看之前是否有过浏览记录),如果为空,这里直接将sub_data插入,如果不为空,这里再判断最新的一条数据是否是今天浏览的,(上面掉了一个=),如果为今天浏览的,就遍历film_history[0].films这个数组,判断里面的data.id是否等于当前数据data.id,(也就是判断今天是否有浏览过这个数据,),如果有,就删除掉这一条数据,然后把当前数据插入进去,(也就是完成了更新数据),如果里面有数据并且最新一条不是今天的就直接把当前数据插入。
然后后面执行的是wx.setStorage上传film_history。
然后看这个页面的渲染。
电影详情页面的背景图片有两张,一张.fd-hd-bg开启绝对定位,脱离文档流,层级设为-2,然后给了一个filter属性,该属性是滤色器,值为blur模糊,然后给了一个transform属性,(但是没有看出这个属性的用处),然后是在.fd-hb上追加的内容,同样设置绝对定位,然后设置层级为-1,也就是这层在.fd-hd-bg的上面,在.fd-hd的下面,然后给他黑色背景和60%的透明。
三、上传照片、分享功能和地理位置的实现
这是上传照片代码完成后的图。
首先用wx.chooseImage从本地相册或相机拍照获取图片,路径为tempFilePath,然后我打印这个路径获取不到这个图片,所以我认为这个只是临时路径,该路径如果直接储存在本地缓存中,可能下次重启程序路径将不可用,所以使用wx.saveFile,将临时路径保存在本地,并且返回一非临时路径savedFilePath,然后再将该路径异步保存在本地缓存中。
由于这个原因,在我上传数据服务器的时候,我怕上传上去的只是临时路径,所以我将wx.uploadFile写在wx.saveFile中,然后上传非临时路径,并且在上传服务器成功后再将数据异步保存在本地缓存中,以免发生上传服务器不成功,而本地缓存中却存在。
问题是wx.setStorage异步缓存的数据在程序重启后,开发者工具找不到数据。
这是分享功能的代码。
这个地方原先是获取到的用户信息的地址,从userinfo中获取的,但是获取的不是用户的当前地址,根据前面看到的程序,获取用户地址在加载主页获取过了,所以可以在前面获取用户详细地址。
首先在这里添加一个变量。
然后在这里获取数据。