WePY 在手机充值小程序中的应用与实践

wepyjs 发布了两个月了,中间经历了很多版本更新,也慢慢开始有一些用户选择 wepyjs 作为开发框架来开发小程序,比如一些线上小程序。

以及一些来自网上的 wepyjs 的相关资源:

demo源码: one图书管理系统

组件:图表控件

因此我也将手机充值小程序在开发过程中 wepyjs 的应用心得分享出来,可以参照对比与传统小程序开发上的差异。

说明:本文不涉及到 wepyjs 的使用与说明,如果需要请参看我的另一篇文章 ”打造小程序组件化开发框架” 或直接参看wepyjs 项目地址

组件化

开发时期望逻辑代码按照业务模块划分,从视觉图上来看,首页可以分为五个模块,分别是:

  • 输入框:Input
  • 下拉历史记录:History
  • 充话费:Mobile
  • 充流量: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 进行开发。

此文已由作者授权腾讯云技术社区发布,转载请注明文章出处

时间: 2024-12-27 13:58:34

WePY 在手机充值小程序中的应用与实践的相关文章

浅谈高大上的微信小程序中渲染html内容—技术分享

大部分Web应用的富文本内容都是以HTML字符串的形式存储的,通过HTML文档去展示HTML内容自然没有问题.但是,在微信小程序(下文简称为「小程序」)中,应当如何渲染这部分内容呢? 解决方案 wxParse 小程序刚上线那会儿,是无法直接渲染HTML内容的,于是就诞生了一个叫做「 wxParse 」的库.它的原理就是把HTML代码解析成树结构的数据,再通过小程序的模板把该数据渲染出来. rich-text 前端精品教程:百度网盘下载 后来,小程序增加了「rich-text」组件用于展示富文本内

使用wepy开发微信小程序的底部导航

前言: 最近公司在做一个微信小程序的项目,用的是类似于vue的wepy框架.我也借此机会学习和实践一下. 小程序官方文档:https://developers.weixin.qq.com/miniprogram/dev/ wepy官方文档:https://tencent.github.io/wepy/document.html#/ wepy小程序项目初始化:wepy小程序入门之项目初始化 今天的目标是开发微信小程序的底部导航 效果图: 1.打开编辑器(我用的是vscode),然后打开微信开发者工

微信小程序中无刷新修改

1.点击事件无刷新修改 原理:onload事件中是把这个分类和品牌的列表全部拿出来,拼接成数组的格式,在小程序中遍历的时候就要把小标(index)给绑定到左侧的品牌上,然后js中获取index的值,就可以动态的修改数组中的下标,右侧的品牌就可以动态的修改了 下面还有另一个方法,到时候会分享

蓝牙在小程序中的应用

1. 背景介绍 蓝牙是爱立信公司创立的一种无线技术标准,为短距离的硬件设备提供低成本的通信规范.蓝牙规范由蓝牙技术联盟(Bluetooth Special Interest Group,简称SIG)管理,在计算机,手机,传真机,耳机,汽车,家用电器等等很多场景广泛使用.蓝牙具有以下一些特点: (1) 免费使用:蓝牙技术免费使用,并且使用的工作频段在2.4GHz的工科医(ISM)频段,无需申请许可证. (2) 功耗低:BLE4.0包含了一个低功耗标准(Bluetooth Low Energy),可

微信小程序中target与currentTarget

如有错误,请纠出,大家一起进步!!! target在事件流的目标阶段:currentTarget在事件流的捕获,目标及冒泡阶段.但事件流处于目标阶段,target与currentTarget指向一样, 而当处于捕获和冒泡阶段的时候,target指向被单击的对象而currentTarget指向当前事件活动的对象.在微信小程序中也可总结为:target指向发生事件的组件,currentTarget指向绑定事件的组件. 下面请看例子: text.wxml: <view class="view1&

微信小程序中的 hover-class

微信小程序中,可以用 hover-class 属性来指定元素的点击态效果.但是在在使用中要注意,大部分组件是不支持该属性的. 目前支持 hover-class 属性的组件有三个:view.button.navigator. 不支持 hover-class 属性的组件,同时也不支持 hover-stop-propagation.hover-start-time.hover-stay-time 这三个属性. 使用方法: <view hover-class="bg_red">这是

微信小程序中的单位

vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%. vh:viewpoint height,视窗高度,1vh等于视窗高度的1%. rpx:rpx单位是微信小程序中css的尺寸单位,rpx可以根据屏幕宽度进行自适应.规定屏幕宽为750rpx.如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素. 微信小程序也支持rem尺寸单位,rem和rpx的换算关系:rem: 规

微信小程序中获取高度及设备的方法

由于js中可以采用操纵dom的方法来获取页面元素的高度,可是在微信小程序中不能操纵dom,经过查找之后发现仅仅只有以下几个方法可以获取到高度 wx.getSystemInfoSync().windowWidth // 获取当前窗口的宽度 wx.getSystemInfoSync().windowHeight // 获取当前窗口的高度 wx.getSystemInfoSync().model // 获取当前采用的设备 wx.getSystemInfoSync().pixelRatio wx.get

微信小程序中的循环遍历问题

比如:如果在微信小程序中要遍历输出 0-9 的数,我们会使用for循环 for(var i=0;i<10;i++){ console.log(i); } 确实结果也是这样: 但是,如果我在循环时同时调用wx的api接口10次,那么输出的结果就会不同(这是产生了闭关的效应) eg:每次调用一次wx.showToast()接口,并在成功时输出循环的值. for(var i=0;i<10;i++){ wx.showToast({ title: 'haha', success:function(){