小程序项目框架搭建
随着小程序越来越火,我们也迎来了新任务 —— 微信小程序。
项目开发前,框架的搭建是很必要的,好的项目框架结构清晰,使用方便,开发高效,且利于维护。吃过框架红利的我对此体验颇深,刚接触我司iOS项目的时候,明显感觉不是一个人写的,项目的整体框架清晰,基础的网络模块,存储模块都进行了合理封装,View层架构也都有规范的布局,刚接触项目小白的我,熟悉起来也很容易。But在看各个子页面的功能代码时,很多都不能直视,完全不是一个水准的东西。尽管子界面代码差些,但有总框架的支撑,维护起来还是很顺手的。搭了一个强健的骨架,包装差些,但轻易还是垮不掉的,反过来就不好说了。
项目要开始了,前端工程师提供了一套框架,里面还有基础的网络请求封装和WEUI基础组件库,基于npm三方管理。东西挺全,通用框架,不过我感觉可以二次封装下,更适用于我们的项目,因此开始了此次的 css 、JavaScript 、html 小白的探坑之旅。
我司小程序为app的翻版,沿用app的api 及 开发模式,所以我比较清楚要什么。
一.全局的字体颜色规范
由于最后需要根据不同的院线,打出不同的包,所有全局颜色的配置就很必要了,都不一样嘛。 同理,设计想修改项目中的字号,不能一个一个去项目里改啊,最好设成全局变量。
这个对于小白来说还是需要思考下的,小程序中没有宏,不能像其它语言中那么干。
(1) 可以用数据绑定的方式,在HTML中绑定控件css 属性的字号和颜色,由 js 层控制,不过总感觉这么写起来太low了,还影响到了 js 和 html 层的结构,下下策。
(2)写多套css ,通过动态改变 class 来变换不同的颜色字号, 恩,强那么一点点,还是low.
(3)经过查资料及尝试,发现第三种方式(tip)在css 可以通过 --name:value 语法定义变量的,且小程序 主界面控件都含在 page 中,so 全局变量出现了,写在文件config.wxss
中。只放个小例子:
page {
--color-a:red;
--color-b:yellow;
--color-c:blue;
}
app.wxss 中引用
@import 'config/config.wxss';
其它子wxss中使用
.title {
text-align: center;
color: var(--color-a);
}
.button {
margin: auto;
width: 40%;
height: 200rpx;
background-color:var(--color-b);
}
这就是我的最终方案了,遗憾的是 var(--color-b) 写起来慢了点。 注意:该配置不包含 nav 及 tabbar 的颜色,需要去 app.json 中手动修改(后期写脚本)
二. 网络层的封装
因为小程序沿用app的api ,url 参数可分为公用参数和每个接口的特有参数,及接口签名。不能每次请求全手打一遍吧,又累出错率又高,所以决定重新封个网络层出来。
要封网络层,项目中网络请求的相关代码需要弄懂,探之旅正式开始。
1.网络请求主文件 wxRequest.js
##主要代码
function wxPromisify(fn) {
return function (obj = {}) {
return new Promise((resolve, reject) => {
obj.success = function (res) {
//成功
resolve(res)
}
obj.fail = function (res) {
//失败
reject(res)
}
fn(obj)
})
}
}
get调用方法
function getRequest(url, data) {
var getRequest = wxPromisify(wx.request)
return getRequest({
url: url,
method: 'GET',
data: data,
header: {
'Content-Type': 'application/json'
}
})
}
对于几乎js零基础的小白来说,这段代码太不友好了,这都什么玩意!
()=>{} function (obj={}){} where the res , what is Promise , 三层返回,各种闭包,那是怎么请求的? 反正我看懂这都都已经眼疲劳了。
wxPromisify 传入函数名,返回一个包装Premise的函数 ,Premise监听异步函数fn,当外部调用getRequest时,执行返回包裹这Premise的函数,异步请求fn(obj)开始执行。 obj 是啥? 是啥啊 {} 空,加个success 和 fail , 各种尝试后,神经大条的打印了下obj,看到了解释,如果obj为空,且外层函数的第一个参数不为空的话,则obj = 第一个参数,妹的,秀操作!!!
另外付promise的传送门,里面有70%的用法吧,漏掉的不是很多,对应上wxPromisify还是够用的。
网络层的调用原理懂了,那么开始二次封装吧。
首先是网络连接,在每次网络调用的时候写
url=http:/group.leying.com/app/init?cinema_id=101....
low爆了有没有,对此封装了url路径管理文件url.js
var host = "http://group.leying.com"
/**
* 自营后台 所有连接的路径
*/
var urlPath = {
movieList: host + "/movie/movie-online-list?",
init: host + "/app/init?"
}
module.exports = {
urlPath : urlPath,
}
通过引入 url.js
就能用key获取到url路径了。
路径的问题解决了,下面解决参数的问题。参数分为公用参数和每个接口的特有参数,公用和特有的合并,去重,进行签名,也封装在url.js
中
// 公共参数
var publicParameter = {
group : '***', // ***
ver : '5.2.2', // 小程序版本
city_id : '499', // 选择城市id 没有为“”
cinema_id: '101', // 选择影院id 没有为“”
session_id: '', // 用户session,没有为“”
**** , // ***
}
var urlParameter = function(parameter) {
// 1.传入的部分 与 公用参数部分 合并
extentObj(parameter,publicParameter)
// 2.细节 参数需要从新排序
parameter = sortObj(parameter)
// 3.进行签名
parameter['.sig'] = getSig(parameter)
// 返回
return parameter
}
// 对象合并的方法 用于 公用参数与特有参数的合并(附带去重功能)
var extentObj = function (obj1, obj2) {
for (let key in obj2) {
if (obj2.hasOwnProperty(key) && (!obj1.hasOwnProperty(key))) {
obj1[key] = obj2[key]
}
}
}
sortObj = function (obj) {
var newkey = Object.keys(obj).sort();
var newObj = {};
for (var i = 0; i < newkey.length; i++) {
newObj[newkey[i]] = obj[newkey[i]];
}
return newObj
}
就贴这几个方法记录下吧。较坑的是签名的地方,知道签名key,知道签名方式,且在签名正确的情况下给我报了N个签名错误。左右反复核对,没发现问题,和和app发出的比对发现了个特色点,连接的参数居然是按字母顺序排序的。要给objc的属性从排序,厉害了,试了半天的sort()无果后,退而求其次。请求成功了,爽酸 ~ 也解了我长久的疑惑,捕获url,把里面的参数换位进行请求,局然成功,后台是怎么比对签名的那。 终于了解了 ~ 从排序的问题你知道么? 太佩服破我们签名的人了,我知道key和格式都破了一下午, 他们真是 666 啦 ~
最终请求优化版:
app.js
中引入url.js
,同时增加 urlService 对象
var urls = require('config/url.js');
var wxRequest = require('util/wxRequest');
var wxApi = require('util/wxApi');
App({
urlService : {
// 网络相关
urls: urls.urlPath, // 所有的自营 urls
urlParameter: urls.urlParameter, // 自营参数加密相关处理
wxRequest: wxRequest, // 调用微信外部链接 封装
wxApi: wxApi // 调用微信内部链接 封装
}
})
因app()对象为全局,在各页面js中请求就容易了index.js
请求为例
Page({
downLoad: function() {
var url = getApp().urlService.urls.init
var parameter = getApp().urlService.urlParameter({
promotion_type : '1', // 我是特有参数
cineme_id : '1111' // 我是特有参数
})
getApp().urlService.wxRequest.getRequest(url, parameter)
.then(this.downSuccess)
.catch((res)=>{
// console.log(res)
})
},
downSuccess (res) {
// console.log(res);
}
})
请求的封装完成,没有污染wxRequest.js
文件,时间主要花在思考封装和学习js上。本计划在wxRequest.js
文件里处理相应数据的,只有errcode不为0,就触发reject,考虑到微信外部请求不光是发向自家后台,格式不同,决定在.then中在加一层数据处理。时间关系,先用这个框架半成品。
负责iOS很长时间了,也看过后台的项目结构,稍微有些项目结构的概念。后期框架计划增加 logic文件夹
处理个别逻辑负责的界面,比如选座,确认订单。model文件夹
,处理响应数据多的接口返回的数据,几个大接口各分一个响应的js文件进行数据处理。service文件夹
,如果有需要,考虑放出来一个。至于界面的view层结构,先探坑,有时间在说。缓存方面,用微信提供的就好啦 ~
呐 ~ 晨会每次都是在看小程序框架、框架、框架 ~ 这就是了 ,刷了很多基础刷出来的。
收获 : Promise 的使用肯定的,css 自定义属性,还有几个没放出来的css 小 tip. 刷了 css、css3 的基础,轮了wxml 的基础组件库,又有机会和设计制定规范了,原来css里的px和设计标的px是两个东西 , 原来MVVM框架核心优势还有数据绑定。趟了js 的几个小坑 ()=>{} , res=>{} , function(obj={}) ,objc 属性排序 ... 吧啦吧啦