WePY 在手機充值小程序中的應用與實踐

wepyjs 發佈了兩個月了,中間經歷了不少版本更新,也慢慢開始有一些用戶選擇 wepyjs 做爲開發框架來開發小程序,好比一些線上小程序。php

以及一些來自網上的 wepyjs 的相關資源:html

demo源碼: one圖書管理系統前端

組件:圖表控件npm

所以我也將手機充值小程序在開發過程當中 wepyjs 的應用心得分享出來,能夠參照對比與傳統小程序開發上的差別。小程序

說明:本文不涉及到 wepyjs 的使用與說明,若是須要請參看個人另外一篇文章 」打造小程序組件化開發框架」 或直接參看wepyjs 項目地址後端

組件化

開發時指望邏輯代碼按照業務模塊劃分,從視覺圖上來看,首頁能夠分爲五個模塊,分別是:api

  • 輸入框:Input緩存

  • 下拉歷史記錄:History服務器

  • 充話費:Mobilebabel

  • 充流量:Traffic

  • 右下角菜單:Menu

以下圖:

在原生小程序中,可使用小程序的模板特性來達到模塊化區別的目地,以下:

<!-- index.wxml -->
<import src="components/input"/>
<import src="components/history" />
<import src="components/mobile" />
<import src="components/traffic" />
<import src="components/menu" />

<view class="pageIndex">
    <template is="comInput" data="{{number}}" />
    <template is="comMobile" data="{{mobileList}}" />
    <template is="comTraffic" data="{{trafficList}}" />
    <template is="comMenu"/>
</view>
// index.js
var Input = require('./components/input');
var History = require('./components/history');
var Mobile = require('./components/mobile');
var Traffic = require('./components/traffic');
var Menu = require('./components/menu');

var MyApp = {
    Input: Input,
    History: History,
    Mobile: Mobile,
    Traffic: Traffic
    Menu: Menu
};
// ....
Page(MyApp);

如此,即可以業務模塊去組織本身的代碼。

小程序的js模塊與wxml模塊並沒有直接關聯,在數據或是事件的命名上須要使用前綴或者是命名空間的方式區分,以防衝突。

好比在Mobile模塊中有一個商品列表list,而且每一個商品都有一個點擊下單事件submit。所以在開發時須要使用mobileList,mobileSubmit或者Mobile.list,Mobile.submit以防止與Traffic模塊衝突,代碼以下:

<block wx:for-items="{{mobileList}}">
    <view class="goods mobile" bindtap="mobileSubmit" data-id="{{item.id}}" data-amount="{{item.amount}}" data-type="{{item.type}}">
        {{item.price}}
    </view>
</block>

使用 wepyjs 直接讓小程序可以支持組件化開發。讓小程序開發可以像 Vue,React 同樣使用自定義組件開發。所以首頁index.wpy 中能夠寫成這樣:

<template>
    <view class="pageIndex">
        <cinput :number.sync="number" />
        <mobile />
        <traffic />
        <menu />
    </view>
</template>
<script>
    import wepy from 'wepy';
    import Input from '../components/input';
    import Menu from '../components/menu';
    import Mobile from '../components/mobile';
    import Traffic from '../components/traffic';

    export default class Index extends wepy.page {

        components = {
            menu: Menu,
            mobile: Mobile,
            traffic: Traffic,
            cinput: Input
        };

        data = {
            number: ''
        };
    }
</script>

在充話費組件components/mobile.wpy中關鍵代碼以下:

<template>
    ....
    <block wx:for-items="{{list}}">
        <view class="goods mobile" bindtap="submit({{item.id}}, {{item.amount}}, {{item.type}})">
            {{item.price}}
        </view>
    </block>
    ....
</template>
<script>
    import wepy from 'wepy';

    export default class Mobile extends wepy.component {
        data = {
            list: []
        };
        methods = {
            submit (id, amount, type) {

            }
        };
        onLoad () {
            // load list;
        }
    }
</script>

對比於之間的代碼,咱們不用再關心是mobileList仍是trafficList。不管是Mobile組件仍是Traffic組件,都有本身的listsubmit方法。保證了組件與組件之間數據的隔離。

Mixin 混合

混合是對組件的複用性的一種補充,使用Mixin能夠很靈活的複用不一樣組件中的相同部分。

好比,爲了作好用戶體驗細節的優化,在面額列表的滾動時加入了陰影控制。當滾到最左邊時,左邊無陰影,滾動到最右邊時,右邊無陰影,滾動到中間時兩邊都出現陰影。以下圖:

陰影由兩個透明漸變效果的樣式決定:left-shadow,right-shadow。

對於Mobile組件和Traffic組件來講,這一功能是二者共有特性,所以可使用Mixin來實現。

建立Mixin文件mixin/scroll.js

import wepy from 'wepy';

export default class ScrollMixin extends wepy.mixin {

    data = {
        shadow: 'left-shadow'
    };
    methods = {
        scroll: function (e) {
            this.shadow = 'left-shadow right-shadow';
        },
        scrollLeft: function (e) {
            this.shadow = 'right-shadow';
        },
        scrollRight: function (e) {
            this.shadow = 'left-shadow';
        }
    };
}

而後在Mobile和Traffic中分別引用當前Mixin便可讓兩個組件同時擁有該功能,參考代碼以下:

<template>
    ....
    <scroll-view scroll-x class="{{shadow}}" bindscrolltoupper="scrollLeft" bindscrolltolower="scrollRight" bindscroll="scroll">
        <block wx:for-items="{{list}}">
            <view class="goods mobile" bindtap="submit({{item.id}}, {{item.amount}}, {{item.type}})">
                {{item.price}}
            </view>
        </block>
    </scroll-view>
    ....
</template>
<script>
    import wepy from 'wepy';
    import ScrollMixin from '../mixin/scroll';

    export default class Mobile extends wepy.component {
        mixins = [ScrollMixin];
        ...
    }
</script>

登陸態維護

小程序提供 wx.login 接口能夠方便的獲取到用戶的 code,經過 code 置換出 session 做爲應用態。session 能夠儲存在 storage 中或者是內存當中,詳情可參照官方文檔

參照官方文檔整理出咱們小程序獲取登陸態的步驟以及應當具有的能力:

  1. 服務器提供一個使用 code 轉換登陸態 session 的接口。

  2. 進入應用時,調用 wx.login() 獲取 code。

  3. 調用接口將 code 轉換爲 session,而且儲存到內存或者storage中。

  4. 發請 request 請求時自動帶上 session 字段。

  5. 由於某些緣由致使 session 失效時,能夠自動再次獲取新的 session 而且發送請求。

畫出流程圖以下:

實現代碼以下:

建立公用模塊 common/global.js 用於存儲全局變量。

export default {
    session: ''
}

在應用啓動時登陸,而且置換 session,而且利用 wepyjs 的 intercept 功能讓每一個 request 都帶上 session。

import wepy from 'wepy';
import api from './common/api';
import G from './common/global';

import 'babel-polyfill';

export default class extends wepy.app {
    onLaunch() {
        wepy.login()
            .then(res => api.getSession(res.code))
            .then(res => {
                G.session = res.session;

                this.intercept('request', { // request 的攔截器,在每次發送request請求時都會加上session
                    config (p) {
                        p.session = G.session;
                        return p;
                    }
                });
            });
    }
}

定義 api 模塊,封裝 request 方法,使其在 session 失效時能再次更新 session 而且發送請求。

// common/api.js
import wepy from 'wepy';
import G from './global';

export default {
    /**
     * code 置換登陸態 session 接口
     */
    getSession (code) {
        return wepy.request({
            url: 'https://yourserver/session',
            data: {
                code: code
            }
        });
    },
    /**
     * 封裝 request 方法,在第一次登錄態失效後自動登陸並轉換 session 後重發請求
     */
    request (data, tryagain) {
        return new Promise ((resolve, reject) => {
            wepy.request(data).then(res = > {
                if (res.data.retCode === 'xxxxx') { // 登陸態驗證失敗
                    if (tryagain) {
                        reject('Something is wrong'); // code 置換 session 後依然返回登陸態驗證失敗
                        return;
                    }
                    return wepy.login() // 多是session過時等緣由,獲取最新 code
                        .then(loginRes => this.getSession(loginRes.code)) // 使用最新code置換 session
                        .then(sessionData => {
                            G.session = sessionData.session;
                            return this.request(data, true); // 重發請求
                        }).catch(reject);
                } else {
                    resolve(res);
                }
            }).catch(reject);;
        });
    },
    getMobileList () {
        let data = {url: 'https://yourserver/api'};
        return this.request(data);
    }
};

所以,在開發時,就不用去關心什麼時候應該登陸的問題,直接調用接口既可。好比在 mobile.wpy 中獲取列表並渲染:

export default class Mobile extends wepy.app {
    async onLoad () {
        this.list = await api.getMobileList();
    }
}

上面解釋的是原始的登陸態維護的一種方式,在手機充值小程序裏,每一個後端接口都有封裝 code 置換 session 的能力,後端接口會優先判斷請求中是否有 session,若是有 session 優先使用 session,若是沒有,使用請求參數中的 code 去置換 session,而後處理請求,再將 session 返回到 response 當中。所以前端流程有些許改變,以下圖:

common/api.js 文件改動以下:

import wepy from 'wepy';
import G from './global';

export default {
    request (data, tryagain) {
        return new Promise((resolve, reject) => {
            if (G.session) {
                wepy.request(data).then(res => {
                    if (res.data.retCode === 'xxxxx') { // 登陸態驗證失敗
                        if (tryagain) {
                            reject('Something is wrong'); // code 置換 session 後依然返回登陸態驗證失敗
                            return;
                        }
                        G.session = '';
                        return this.request(data, true);
                    } else {
                        resolve(res);
                    }
                }).catch(reject);
            } else {
                wepy.login() // 多是session過時等緣由,獲取最新 code
                    .then(loginRes => {
                        data.data.code = loginRes.code;
                        return wepy.request(data); // 使用 code 發送 request 請求
                    }) 
                    .then(res => {
                        G.session = res.session; // 返回結果中 設置 session
                        resolve(res);
                    }).catch(reject);
            }
        });
    }
};

第三方組件

小程序中並不能像H5同樣直接使用alert彈出消息提示,所以能夠選擇使用 wx.showToast 的API進行消息提示,可是官方只支持success 和 loading 兩種樣式。從新寫一個 toast 組件成本略高,所以考慮直接使用現成的 wepy-com-toast 組件。使用方法以下:

1 . 安裝組件

npm install wepy-com-toast --save

2 .無緩存編譯

wepy build --no-cache

3 .須要的組件中引入 toast 組件

<template>
 <toast />
</template>
<script>
 import wepy from 'wepy';
 import Toast from 'wepy-com-toast';

 export default class Index extends wepy.page {
     components = {
         toast: Toast
     };
 }
</script>

4 .調用

this.$invoke('toast', 'show', {
 title: '系統繁忙',
 img: 'https://yourpicture.com/sad.png',
});

實現效果以下圖:

數據上報

[MTA是騰訊自家的數據分析平臺,在小程序發佈後MTA平臺很快的就支持了小程序的數據上報。所以手機充值選擇MTA作爲數據上報平臺,具體步驟以下:

1 .在MTA官網註冊應用。

2 .在mp平臺,小程序開發設置中,將https://pingtas.qq.com 添加爲可信域名。

3 .安裝 mta-analysis 模塊:npm install mta-analysis --save

4 .在 app.wpy 中添加初始化代碼。

import wepy from 'wepy';
import mta from 'mta-analysis';

export default class extends wepy.app {
    onLaunch() {
        mta.App.init({
           "appID":"xxxx", // 註冊後獲得的appID
           "eventID":"xxxx", // 註冊後獲得的eventID
           "statPullDownFresh":true, // 使用分析-下來刷新次數/人數,必須先開通自定義事件,並配置了合法的eventID
           "statShareApp":true, // 使用分析-分享次數/人數,必須先開通自定義事件,並配置了合法的eventID
           "statReachBottom":true // 使用分析-頁面觸底次數/人數,必須先開通自定義事件,並配置了合法的eventID
        });
    };
}

這樣就完成了MTA的初始化工做,在每一個頁面的 onLoad 事件中加入 init 事件完成頁面的上報。

export default class Index extends wepy.page {
    onLoad () {
        mta.Page.init();
    };
}

在 app.wpy 中加入報錯上報。

export default class extends wepy.app {
    onError () {
        mta.Event.stat("error",{});
    };
}

以及在其它業務邏輯代碼上加入一些自定義事件上報,好比下單上報,支持上報等等。

mta.Event.stat("payed",{});

結束語

至此,基本介紹完了 wepyjs 在手機充值項目的應用了,剩下的就是業務代碼的開發了。wepyjs 經過不停的版本更新迭代去吸取一些傳統框架優秀特性融入其中,好比:組件通信、props傳值、Mixin、Slot、攔截器等等。也但願在之後能有更多的小程序開發者使用 wepyjs 進行開發。

此文已由做者受權騰訊雲技術社區發佈,轉載請註明文章出處

相關文章
相關標籤/搜索