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 进行开发。

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

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

  1. wepy框架构建小程序(1)

    wepy框架构建小程序(1) 基本操作: # 安装脚手架工具 npm install wepy-cli -g # 创建一个新的项目 npm init standard myproject # 进入新项 ...

  2. 使用wepy开发微信小程序商城第二篇:路由配置和页面结构

    使用wepy开发微信小程序商城 第二篇:路由配置和页面结构 前言: 最近公司在做一个微信小程序的项目,用的是类似于vue的wepy框架.我也借此机会学习和实践一下. 小程序官方文档:https://d ...

  3. 使用wepy开发微信小程序商城第一篇:项目初始化

    使用wepy开发微信小程序商城 第一篇:项目初始化 前言: wepy小程序项目初始化的操作,官方文档看了好几遍,感觉写得不是很清楚. 这篇写得挺好的:小程序开发之wepy 1.初始化项目 (1)全局安 ...

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

    大部分Web应用的富文本内容都是以HTML字符串的形式存储的,通过HTML文档去展示HTML内容自然没有问题.但是,在微信小程序(下文简称为「小程序」)中,应当如何渲染这部分内容呢? 解决方案 wxP ...

  5. 网页或微信小程序中使元素占满整个屏幕高度

    在项目中经常要用到一个容器元素占满屏幕高度和宽度,然后再在这个容器元素里放置其他元素. 宽度很简单就是width:100% 但是高度呢,我们知道的是height:100%必须是在父元素的高度给定了的情 ...

  6. 微信小程序中rpx与rem单位使用

    原作者: 小小小   来自: 授权地址 本文讲解rpx和rem应用于微信小程序,如果你还没有入门,建议先从下面看起: 微信小程序官方文档web app变革之remrpx单位官方文档rpx单位基础介绍 ...

  7. 微信小程序中在swiper-item中遍历循环添加多个数据内容(微信小程序交流群:604788754)

    在小程序中为了实现一个<swiper-item>中添加多个内容重复的标签,那就需要使用wx:for循环.如果按小程序的简易教程,循环加在block中,而swiper-item放在里面.所有 ...

  8. 开发微信小程序中SSL协议的申请、证书绑定、TLS 版本处理等

    在上篇随笔<基于微信小程序的系统开发准备工作>介绍了开发微信小程序的一些前期的架构设计.技术路线 .工具准备等方面内容,本篇随笔继续这个步骤,逐步介绍我们实际开发过程中对SSL协议的申请及 ...

  9. 在微信小程序中使用富文本转化插件wxParse

    在微信小程序中我们往往需要展示一些丰富的页面内容,包括图片.文本等,基本上要求能够解析常规的HTML最好,由于微信的视图标签和HTML标签不一样,但是也有相对应的关系,因此有人把HTML转换做成了一个 ...

随机推荐

  1. css3公共样式

    温馨提示:一下css封装,建议按需使用,否则会造成很大的代码冗余,且很多样式会造成不符合预期的效果,建议合理使用 <a href="https://meyerweb.com/eric/ ...

  2. js之选项卡效果(淘宝侧边栏)

    HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <ti ...

  3. apply函数应用

    (1)找到数组中最小或最大的数字 var v = [1,23,4,9]; console.log(Math.min.apply(Math,v));

  4. Python递归输出字典所有不同深度的路径

    应用场景 假设有这样一个字典结构test_dict = {'a':{'b':{'c':1}},'d':2},test_dict其实可以看作是一种树状结构,其中每个叶子节点深度不一定相同,如果我们希望输 ...

  5. BZOJ1017: [JSOI2008]魔兽地图DotR【树形DP】【玄学】

    Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Anc ...

  6. Java 自定义FTP连接池

    转自:https://blog.csdn.net/eakom/article/details/79038590 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn ...

  7. sublime python运行插件

    Tools->New plugin 粘贴下面代码,在插件目录新建文件夹,保存 import sublime, sublime_plugin import os class ExampleComm ...

  8. 修改selinux出现setsebool: SELinux is disabled.的解决方法

    1.vi /etc/vsftpd/vsftpd.conf # You may specify an explicit list of local users to chroot() to their ...

  9. Google、IBM和Lyft开源其大型微服务系统管理工具Istio

    Istio 的优势 集群规模可视性:在故障状况出现时,运营人员需要利用多种工具以始终关注集群运行状况并分析微服务状态图表.Istio 项目能够监控与应用程序及网络活动相关的数据,利用 Promethe ...

  10. Linq 分组(group by)后列变行

    表一: 表二: 已知表一的List,想得到表二的结果: var query = from c in t.AsEnumerable() group c by new { pingming = c.Fie ...