前言
家里书买了不少,但来不及看也不记得自已都有什么书了;另外有时想看一本书买了回来,才发现身边有人已经买过了,是可以借来看的。因此,一直想出一个个人书籍管理的工具,并能支持熟人间书籍借阅的功能。
微信小程序,在微信发布整整6年后的2017年1月9日发布,号称纯功能性、用完即走、低成本、高效率。因此,何不就着这平台体验一把。本文就开发一个个人书架管理的WX小程序的过程中,对遇到的折腾点、问题点和想法做个记录,以备参考。
1. 开发者工具
![Uploading gh_7ddb46850a7d_258_730288.jpg . . .]
先来说说开发者工具的使用,帮助提升编码效率。
(1)调试 - AppData
在调试面板的AppData页可以查看当前打开各页中Data的内容,这样就不用再为了查看变量而输出console.log了;对于数据缓存Storage也是同样的。
(2)真机本地调试
小程序访问远程后台是有https+备案域名的要求,但开发过程中是希望能避开这些限制,好在开发工具已经支持在开发环境下不校验请求域名、TLS版本以及HTTPS证书,将如下选项勾选即可:
同时,当然也希望能够在本地调试后台,那么由于开发环境可不校验域名,因此我采用让手机和开发机连同一个局域网,通过局域网ip访问即可做到真机的本地调试。当然,如果非要通过域名的话,则可以考虑用一些软件工具在本地虚一个域名出来。
(3)wx.request出现400的坑
提前提一点,如果在调用中出现如下错误:
![](https://img.haomeiwen.com/i2434145/466e456ddf381784.png)
则是由于请求的header的Content-type写法变了,需要配置为对应的type就好了
header:{
"Content-Type":"json"
},
2. WX小程序前端
前端主要基于官方提供的微信开发者工具,采用类HTML+JS+CSS的方式进行开发,单个小程序应用大小不能超过10M。
(1)flex布局
实现可伸缩的布局方式,代码参考如下
.kind-list-item-hd {
padding: 30rpx;
display: flex;
align-items: flex-start;
transition: opacity .3s;
通过flex-direction属性还能控制布局方向。
- row :从左到右的水平方向为主轴
- row-reverse:从右到左的水平方向为主轴
- column:从上到下的垂直方向为主轴
- column-reverse从下到上的垂直方向为主轴
不过在并列的几个view中,想要最右的view靠右排列,而其他的依然靠左,则没有找到现成的配置属性;最后采用了扩展中间view的宽度的方式,将最右边的view“排挤”到最右侧以达到效果。
.kind-list-info {
flex-direction:column;
width: 63%;
}
(2)TabBar不能自动打开扫描功能
通过如下代码可以调用设备摄像头进行扫描,并在扫描成功success时将扫描结果导航到其他目标页面。
scanCode: function () {
console.log('scanCode')
wx.scanCode({
success: function (res) {
wx.navigateTo({
url: '../scanner/scanner?result=' + res.result
})
},
fail: function (res) {
}
})
}
不过想要在tarbar中添加一个按钮,实现点击后直接打开摄像头,通过在tarbar对应的path页面中注册onLoad函数,并在onLoad添加以上代码,发现在设备中并没有生效(不过在开发工具中使用到时打开了文件对话框),因此最后改用按钮的方式来实现了。
(3)网络通信
通信方式如下四种,一类是消息通信,一类是文件通信。+ https请求:
- wx.request(object)
- 文件上传:wx.uploadFile(object)
- 文件下载:wx.downloadFile(object)
- WebSocket:wx.connectSocket(object)等
其中,消息通信分为短连接的https请求和可实现长连接的WebSocket通信,WebSocket通信还可实现服务器端向客户端推送的能力,因此具体实现根据应用场景来选择。
(4)API执行fail时获取错误信息
wx.navigateTo有一个约束,就是不能导航到TabBar的页面,否则会抛错,错误信息可以再fail中捕获到,并通过error来查看。
wx.navigateTo({
url: '../scanner/scanner?result=123',
success: function () {
console.log('scanCode success')
},
fail: function (error) {
console.log(error)
}
})
(5)切换Tab页时的数据传输
如上所说,切换的页面是TabBar时,需要使用wx.switchTab,该api不能带数据参数,因此若要解决其他页面切换到Tab页并实现数据更新,有如下两种思路:
- 使用全局变量globalData
- 使用数据缓存
此次使用的是全局变量globalData的方式,通过每次Tab页显示时会调用的onShow函数来加载更新后的全局变量,参考代码如下:
onShow: function() {
console.log('onShow')
var that = this
that.setData({
bookListSize: app.globalData.bookListSize,
bookList: app.globalData.bookList
})
}
(6)引用weui效果不一致的问题
参考https://weui.io/ 来引用weui的一些效果,若原样照搬html版的会发现效果不一致,在小程序示例工程中带的weui包(/page/common/lib/weui.wxss)中的效果还是不一致,有的样式被拆开了,需要注意。例如之前在微信公众平台开发者社区提的一个问题:关于WEUI(loadmore)的效果不一致的问题
weui.css
.weui-loadmore_line .weui-loadmore__tips {
position: relative;
top: -0.9em;
padding: 0 .55em;
background-color: #FFFFFF;
color: #999999;
}
/* 到小程序中变成这样了 */
weui.wxss
.weui-loadmore__tips_in-line {
position: relative;
top: -0.9em;
padding: 0 .55em;
background-color: #FFFFFF;
color: #999999;
}
(7)修改输入框placeholder文字的样式
input有个placeholder-class属性,可以自定义样式
<input placeholder-class="psection" maxlength="10" placeholder="最大输入长度10" />
.psection{
color: #FFC0CB;
}
参考:http://www.henkuai.com/forum.php?mod=viewthread&tid=15684
(8)搜索功能
收藏的书多了,必然少不了搜索。观察其他app或小程序的实现方式,会发现一般在主页置一个输入框;当点击输入框时,会跳转到单独的搜索页面,通过该页面可以提供热门搜索、搜索记录、分类搜索等更多功能,这样不影响原主页的处理。
![](https://img.haomeiwen.com/i2434145/25baa2b0d2f23f57.png)
这里的引入了wxSearch组件,其已经实现了自定义热门搜索、搜索历史、搜索建议的功能。在这基础之上,配套调整了CSS样式,根据需要目前只取了搜索历史功能(热门搜索词的选择有待算法研究),优化搜索历史框消失、重现的流程,添加对弹出的虚拟键盘点击搜索键的监听处理,并添加了清空搜索按钮功能。
![](https://img.haomeiwen.com/i2434145/5a4cc6314b6752a7.png)
![](https://img.haomeiwen.com/i2434145/a9e521332a233995.png)
(9)意见反馈
任何一个应用收集用户的反馈信息或与用户互动是十分重要的。
一般有两种方式:
- 在线客服:微信小程序提供了客服消息的支持,只要添加如下代码即可;点击对话图标即可进入客服对话框
/**
* 用户点击右上角分享
*/
<view class="weui-cells weui-cells_after-title">
<view class="weui-cell weui-cell_switch">
<view class="weui-cell__bd">在线客服</view>
<contact-button size="40" session-from="custService"></contact-button>
</view>
</view>
![](https://img.haomeiwen.com/i2434145/2b98c85d55e0180c.png)
在这基础之上,还可以接入一些第三方智能客服、智能机器人,笔者在此尝试了V5智能客服,以下这些对话都是V5机器人自动回答的哦~
![](https://img.haomeiwen.com/i2434145/2f566a8175908029.jpg)
- 在线留言(表单):这种方式类似于离线提交表单,有一些现成的平台能够提供功能(比如金数据),不过由于小程序目前(2017.6)还不支持外部链接,所以没有办法引用,后续期待小程序能支持外链,或者自己来实现吧。
金数据表单效果图
3. WX小程序后端
后端服务基于NodeJS+MySql来实现。一开始为方便结构扩展,数据库拟用Mongo,但Mongo的云数据库相比关系数据库太贵,所以还是选择了MySql。
PS:附当前最新的5.7.18版本ZIP包在Windows环境下的安装过程参考:http://www.jb51.net/article/112661.htm
(1)Node的日志输出
日志框架有多种,看到提的比较多的有三种:
- Log4JS:coloured console logging、可以设置输出等级、可以配置输出格式;参考:http://cnodejs.org/topic/53e3b578fdce29004e0d1387
- Winston :扩展性好,支持多传输;参考:http://blog.csdn.net/iefreer/article/details/34442183
- Bunyan:可以让不同类别的日志输出到不同的地方,采用json格式,可方便进行过滤。
这里采用Log4JS就足够了,配置参考:
{
"appenders": [{
"type":"clustered",
"category": "app",
"appenders": [
{
"type": "console"
},
{
"type": "dateFile",
"filename": "./log//app.log",
"pattern": "-yyyy-MM-dd",
"alwaysIncludePattern": true
}
],
"replaceConsole": true
}]
}
var log4js = require('log4js')
var log = log4js.getLogger('app');
(2)严格模式
JS中有一种写法是'use strict';,这个表示严格模式,简单介绍一下,严格模式的目的是:
- 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为未来新版本的Javascript做好铺垫。
而由此带来的影响请注意:
- 如果在语法检测时发现语法问题,则整个代码块失效,并导致一个语法异常。
- 如果在运行期出现了违反严格模式的代码,则抛出执行异常。
参考:Javascript 严格模式详解;使用严格模式有什么优点
(2)Node进程守护
Node进程管理用pm2,防止未捕捉的异常中断程序没起来。
pm2 start ibookshelf.json
# ibookshelf.json
{
"name": "ibookshelf",
"script": "app.js",
"cwd": "./",
"exec_mode": "fork",
"watch": false,
"env": {
"NODE_ENV": "production",
"DEBUG_SDK": "yes"
}
}
不过要注意的是watch配置用来监听文件是否变化,若变化则自动重启。那如果把日志文件也生成在了工程目录下,则文件在不停的打日志,应用就会不停的重启了。。这时可以考虑把日志外迁至独立的目录,或者使用ignore_watch参数,配置参考:PM2实用入门指南
4. 数据库(MySql / Mongodb)
(1)MySQL中TIMESTAMP与DATETIME的区别
- TIMESTAMP把客户端插入的时间从当前时区转化为UTC(世界标准时间)进行存储;查询时将其又转化为客户端当前时区进行返回,这也就意味着查询的结果会和机器时区设置有关。
- DATETIME不做任何改变,原样输入输出。
另外,从mysql5.6开始,DATETIME也支持设置默认值和更新了。
CREATE TABLE `test` (
`id` int(11),
`meta_updateAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)```
参考:[MySQL5.6时间类型timestamp和datetime有了重大改变](http://www.linuxidc.com/Linux/2012-09/71430.htm)
######(2)Mongoose插入数据库时的命名问题
首先在创建数据库连接时需指定库名,否则会默认连接test库
```JavaScript
mongoose.connect("mongodb://localhost:27017/数据库库名");
另一个命名问题是关于集合的,在定义model时,如果不通过如下方式定义集合名时,mongoose默认采用model名,并且判断model名是否可数,若可数的话会采用module名+‘s’的方式(如userinfos)
var UserInfo = mongoose.model('UserInfo', UserInfoSchema, '集合名');
5. 其他
(1)JS日期格式化转换方法
引入moment.js:http://momentjs.cn/
npm install moment
var moment = require('moment');
moment('2017-06-08T00:24:07.231Z').format('YYYY-MM-DD'); //2017-06-08
之前还使用了另一种方式,对Date原型添加如下方法:
Date.prototype.format = function(fmt) {
var o = {
"M+" : this.getMonth()+1, //月份
"d+" : this.getDate(), //日
"h+" : this.getHours(), //小时
"m+" : this.getMinutes(), //分
"s+" : this.getSeconds(), //秒
"q+" : Math.floor((this.getMonth()+3)/3), //季度
"S" : this.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt)) {
fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
}
for(var k in o) {
if(new RegExp("("+ k +")").test(fmt)){
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
}
}
return fmt;
}
然后就可以这样调用了:
var time1 = new Date().format("yyyy-MM-dd hh:mm:ss");
var time2 = new Date().format("yyyy-MM-dd");
参考:http://www.cnblogs.com/tugenhua0707/p/3776808.html
此外,发现在NodeJS中写入new Date()或Date.now()的时间都是格林威治时间,比北京时间慢8小时,而原有设置时区的方式(process.env.TZ = "Asia/Shanghai";)不可用,因此改用如下方式:
process.env.TZ = "Asia/Shanghai";
Date.prototype.TimeZone = new Map([
['Europe/London',0],
['Asia/Shanghai',+8],
['America/New_York',-5]
])
Date.prototype.zoneDate = function(){
if(process.env.TZ == undefined){
return new Date();
}else{
for (let item of this.TimeZone.entries()) {
if(item[0] == process.env.TZ){
let d = new Date();
d.setHours(d.getHours()+item[1]);
return d;
}
}
return new Date();
}
}
然后这样调用就可以获取当前时间了:
new Date().zoneDate()
(2)JS异步批量请求时,保持返回数据顺序和请求的顺序一致
比如收到一组按收藏时间排序的ISBN码,然后通过ISBN查询图书信息,将收到的图书信息存储在数组中并保持和ISBN的顺序一致;但由于是通过JS异步并发发起http请求,因此收到图书信息的顺序并不一致。
对这种情况拟两种解决方式:
- 提前生成一个数组,将ISBN作为KEY按顺序放好了,待图书信息返回时,放到对应的位置即可,直至所有信息返回
- 收到所有数据后,再按照一定规则进行排序处理(例如按照收藏时间、或匹配ISBN顺序)
- 将异步操作改为同步(如Promise,参考:http://blog.csdn.net/qq_31383345/article/details/60574200)
第一种方式相对更简单,且未放弃异步相对于同步的优势,因此在这里采用了第一种方式。
后记
由此,基本完成一个简单的小程序功能,该小程序叫“厉害了我的书”,现已发布,欢迎微信扫码体验。小程序发展非常迅速,新增功能和特性都很频繁,WX小编经常大半夜推送新功能信息,令人振奋。
后续将在此基础上不断扩充功能,有新的坑点、亮点和想法笔者也会有新的记录和发布 (ง •_•)ง
![](https://img.haomeiwen.com/i2434145/225cb06d3757c83d.jpg)
网友评论