十一期间没什么事,我试着写了一个微信小程序WeSJTU
。现在,回过头来,把自己开发小程序的心得给总结一下。
构思
微信小程序的文档,比较难的部分,如数据绑定,其思想和AngularJS
是非常相近的,而所谓的WXSS
,基本上可以认为是CSS
,只是不方便用SCSS
了——WXSS原则上不支持级联,所以整个文档看下来基本上就能上手了。
先从简单有意思的开始吧,所以我设想了三个Tab
:
同去。同去网是交大活动发布的主要阵地,它有很完善的API,可以通过GET请求返回活动列表、活动详情的JSON数据,另外还支持分页。
2048. 根据别人写的数字2048,打算改成文字2048——苟利国家生死以,岂因祸福避趋之,蛤蛤...
反馈。这一部分,想做一个简单的反馈功能,用户可以在小程序里反馈,我可以在网页上查看反馈内容列表。
代码
同去
活动列表页面,前端可以用小程序的列表渲染很方便地实现。
<scroll-view class="acts-list" scroll-y="true" bindscrolltolower="lower"> <block wx:for="{{actsList}}"> <view class="act-item" index="{{index}}" id="{{item.actid}}" catchtap="redictDetail"> ... </view> </block> <view class="load-more" hidden="{{moreHidden}}"> <view class="load-content"> <text class="weui-loading"></text> <text class="loading-text">玩命加载中</text> </view> </view> </scroll-view>
由于同去网不支持HTTPS
,而小程序的wx.request
发起的是HTTPS请求,所以需要在后端将请求转发一下。后端我用的是Node.js
.
router.get('/acts', function(req, res, next) { var query = require('url').parse(req.url, true).query; var offset = query.offset; var order = query.order; var indexUrl = "http://tongqu.me/index.php/api/act/type?type=0&offset=" + offset + "&order=" + order; http.get(indexUrl, function(response) { var source = ""; response.on('data', function(data) { source += data; }); response.on('end', function() { source = JSON.parse(source); var actsList = []; var acts = source.result.acts; var actsLength = acts.length; for (i = 0; i < actsLength; i++) { var poster = acts[i].poster; var status = acts[i].time_status_str; var status_style = ''; if (!poster) { var index = Math.round(Math.random() * 6); var array = [1, 2, 4, 5, 7, 8, 9]; poster = "http://tongqu.me/images/act_default_poster/" + array[index] + ".jpg"; } if (status == "人数已满") { status_style = "act-status-full"; } if (status == "未开始报名") { status_style = "act-status-todo"; } if (status == "报名已结束") { status_style = "act-status-done"; } var act = { actid: acts[i].actid, poster: poster, name: acts[i].name, status: status, status_style: status_style, time: acts[i].start_time.substr(5) + " ~ " + acts[i].end_time.substr(5), location: acts[i].location, source: acts[i].source, views: acts[i].view_count, members: acts[i].member_count }; actsList.push(act); } res.send({ actsList: actsList }); }); }); });
活动详情页面,由于活动内容有文字有图片,所以列表渲染的思路是——文字就渲染文字,图片就渲染图片。
<scroll-view class="act-contents" scroll-y="true"> <block wx:for="{{actContents}}"> <view wx:if="{{item.viewIf}}" class="act-paragraph"> <text wx:if="{{item.textIf}}" class="act-text">{{item.text}}</text> <view wx:if="{{item.imageIf}}" class="{{item.imageCenter}}"><image mode="aspectFit" src="{{item.image}}"></image></view> </view> </block> </scroll-view>
为了配合前端,后端需要做好数据的处理。
router.get('/act', function(req, res, next) { var query = require('url').parse(req.url, true).query; var id = query.id; var indexUrl = "http://tongqu.me/index.php/api/act/detail?id=" + id; http.get(indexUrl, function(response) { var source = ""; response.on('data', function(data) { source += data; }); response.on('end', function() { source = JSON.parse(source); var main_info = source.main_info; var poster = main_info.photolink; var status = main_info.time_status_str; var status_style = ''; if (!poster) { var index = Math.round(Math.random() * 6); var array = [1, 2, 4, 5, 7, 8, 9]; poster = "http://tongqu.me/images/act_default_poster/" + array[index] + ".jpg"; } if (status == "人数已满") { status_style = "act-status-full"; } if (status == "未开始报名") { status_style = "act-status-todo"; } if (status == "报名已结束") { status_style = "act-status-done"; } var actContents = []; var $ = cheerio.load(source.body); if ($("p").length) { $("p").each(function() { var text = $(this).text().trim(); var textIf = true; if (!text) { textIf = false; } var $img = $(this).children("img"); var imageIf = false; var image = ""; var imageCenter = ""; if ($img.length !== 0) { imageIf = true; image = $img.attr("src"); imageCenter = "image-center"; } var viewIf = true; if (!(textIf || imageIf)) { viewIf = false; } var actContent = { viewIf: viewIf, text: text, textIf: textIf, image: image, imageIf: imageIf, imageCenter: imageCenter }; actContents.push(actContent); }); } else { var actContent = { viewIf: true, text: $.text().trim(), textIf: true, image: "", imageIf: false, imageCenter: "" }; actContents.push(actContent); } var actDetail = { poster: poster, name: main_info.name, status: status, status_style: status_style, time: main_info.start_time.substr(5) + " ~ " + main_info.end_time.substr(5), location: main_info.location, source: main_info.source, actContents: actContents }; res.send(actDetail); }); }); });
2048
2048,代码的思路还是比较清晰的——通过触摸动作返回的坐标值判断手指滑动方向,然后移动合并,判断输赢,随机插入等。其中,数字转文字的代码是通过循环实现的,简单粗暴。
number2word: function(arr) { var numbersArray = [0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384]; var wordsArray = ['他', '苟', '利', '国', '家', '生', '死', '以', '岂', '因', '祸', '福', '避', '趋', '之']; var wordnumbers = arr; for (var i = 0; i < 4; i++) { for (var j = 0; j < 4; j++) { var index = numbersArray.indexOf(wordnumbers[i][j].number); wordnumbers[i][j].word = wordsArray[index]; } } return wordnumbers; }
用模态框提醒游戏结束。
<modal class="modal" confirm-text="吼啊" cancel-text="不吼" hidden="{{failHidden}}" bindconfirm="modalConfirm" bindcancel="modalCancle"> <view>图样图森破!</view> <view>重新开始,吼不吼啊?</view> </modal> <modal class="modal" confirm-text="吼啊" cancel-text="不吼" hidden="{{successHidden}}" bindconfirm="modalConfirm" bindcancel="modalCancle"> <view>比一般人不知高到哪里去!</view> <view>再来一次,吼不吼啊?</view> </modal>
感觉膜得也太暴力了...
反馈
前端是一个表单,反馈内容由用户输入,反馈者的基本信息由小程序的wx.getUserInfo
获得。
<form class="feedback-form" bindsubmit="formSubmit"> <view class="feedback-form-wrapper"> <view class="feedback-title">期待您的反馈</view> <view class="input-wrapper"> <input class="feedback-input {{inputStyle}}" name="feedback" placeholder="建议或吐槽..." bindfocus="inputFocus" bindblur="inputBlur" /> </view> <view class="btn-wrapper"> <button class="feedback-btn" formType="submit" type="primary" plain="true">提交</button> </view> </view> </form>
后端将前端通过POST请求提交的表单数据写入到SQLite
中。
router.post('/feedback', function(req, res, next) { var nickname = req.body.nickname; var gender = req.body.gender; var content = req.body.content; if (gender == 1) { gender = "男"; } else if (gender == 2) { gender = "女"; } else { gender = "未知"; } db.run("INSERT INTO feedback (time, nickname, gender, content) VALUES ($time, $nickname, $gender, $content)", { $time: moment().format('MM-DD HH:mm'), $nickname: nickname, $gender: gender, $content: content }, function(err) { var data = "success"; if (err) { data = "fail"; } res.send(data); }); });
然后,通过网页就可以很方便地查看了。
<div class="feedback"> <div class="feedback-wrap"> <div class="feedback-title"> <p>反馈列表</p> </div> <table class="feedback-table"> <thead> <tr> <th class="col1">时间</th> <th class="col2">昵称</th> <th class="col3">性别</th> <th class="col4">内容</th> </tr> </thead> <tbody> <% var i=0; feedbackList.forEach(function(item) { if(i<5) { %> <tr> <td class="col1td"><%= item.time %></td> <td class="col2td"><%= item.nickname %></td> <td class="col3td"><%= item.gender %></td> <td class="col4td"><%= item.content %></td> </tr> <% } i++; }) %> </tbody> </table> </div> </div>
效果
同去
tongqu
tongqu-detail
2048
2048-entry
2048
反馈
about
小程序WeSJTU的前端代码已经在GitHub
上开源了——点此前往,欢迎学习交流。
个人技术博客 biebu.xin,原文链接——微信小程序WeSJTU开发心得 - 别不信