微信小程序WeSJTU开发心得
2017-01-31 20:55 阅读(264)

十一期间没什么事,我试着写了一个微信小程序WeSJTU。现在,回过头来,把自己开发小程序的心得给总结一下。

构思

微信小程序的文档,比较难的部分,如数据绑定,其思想和AngularJS是非常相近的,而所谓的WXSS,基本上可以认为是CSS,只是不方便用SCSS了——WXSS原则上不支持级联,所以整个文档看下来基本上就能上手了。

先从简单有意思的开始吧,所以我设想了三个Tab

代码

同去

活动列表页面,前端可以用小程序的列表渲染很方便地实现。

<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开发心得 - 别不信