应一位小程序开发者的需求,对微信打赏接口进行测试。本人接触微信小程序的时间不长,解析微信事项打赏
项目结构目录树
Development Notices:
-
生命周期函数
- 在使用生命周期函数时,当全局变量注册页面。数据的传递顺序为
data
>Onload(): function
>OnReady(): function
这意味着我们需要将获取或设置的变量设置为全局,在生命周期函数执行时,依次调用
- 在使用生命周期函数时,当全局变量注册页面。数据的传递顺序为
-
this变量作用域
- 直接修改
this.data
而不调用this.setData
是无法改变页面的状态的,还会造成数据不一致
- 直接修改
-
- 当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台。需要注意的是:只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。
-
his.setData - Page.prototype.setData()
- setData 函数用于将数据从逻辑层发送到视图层(异步),同时改变对应的 this.data 的值(同步)。
-
that变量作用域
- 微信官方并未讲明
that
变量的作用域,笔者拿一段JS的原型链demo与其进行比较
- 微信官方并未讲明
微信给出的demo
Page({
data: {
text: "This is page data."
},
onLoad: function(options) {
// Do some initialize when page load.
},
onReady: function() {
// Do something when page ready.
},
onShow: function() {
// Do something when page show.
},
onHide: function() {
// Do something when page hide.
},
onUnload: function() {
// Do something when page close.
},
onPullDownRefresh: function() {
// Do something when pull down.
},
onReachBottom: function() {
// Do something when page reach bottom.
},
onShareAppMessage: function () {
// return custom share data when user share.
},
onPageScroll: function() {
// Do something when page scroll
},
// Event handler.
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
},
customData: {
hi: 'MINA'
}
})
JS原型链修改变量的值
var that = this;
//这里我们定义一个全局指针,方便指向之后需要遍历变量需要获取或设置的值
function Animal(name){
that.name= name;
}
//为原型链指定的变量给定一个初值,等待对象调用
Animal.prototype.getNames = function(){
Console.log(that.name);
}
//实例化类的索引
var animal1 = new Animal('Kate');
var animal2 = new Animal('LUk')
//调用共有原型链方法,把之前实例化索引的值,利用that指针输入到console
animal1.getNames();
animal2.getNames();
One Step
对于微信小程序,微信官方统一封装了wx模板,wx:for指定的模板变量对应同一目录下JS的Page节data部分
1.为渲染一个包含多节点的结构块使用block:for
标记
2.设置wx:for
绑定数组为data
Json中的chatList
,wx:key
绑定chatList
索引为time
3.wx:if
判定orientation
该事项是否已经移除
Second Step
编写indexJs思路
1.通过微信的内置方法getApp()拿到全局应用的数据,在文档中,我们可以看到以下两行
-
App()
在必须app.js
中注册,且不能注册多个。 - 不要在定义于
App()
内的函数中调用getApp()
,使用this
就可以拿到应用实例。
2.根据上文生命周期函数的文档解释,我们首先在data
数组里使用用户数据userInfo
, 聊天数据列表chatList
作为被设置的变量
3.如上文所述,我们用一个that
指针替换指向全局实例指针this
,便于在需要在执行生命周期函数的时候,设置想要设定数据的值,关于userInfo
变量,参考上文原型链定义,将getUserInfo
方法添加到app.js文件中,以便获取或设置全局数据,不受上下文作用域影响。
4.当执行到onReady
函数时,监听页面初次渲染完成,小程序从后台进入前台显示,回调全局方法addChatList
将之前设置在data
中的变量 chatList
传进 chatListData
数组
5.在addChatList
方法中设置需要的Json格式
index.js
//index.js
//获取应用实例
var app = getApp();
var that;
var chatListData = [];
//页面数据设置
Page({
data: {
motto: 'Hello World',
userInfo: {},
//添加用户聊天列表
chatList: []
},
//事件处理函数
bindViewTap: function() {
wx.navigateTo({
url: '../logs/logs'
})
},
onLoad: function () {
that = this;
//调用应用实例的方法获取全局数据
app.getUserInfo(function(userInfo){
//更新数据
that.setData({
userInfo:userInfo,
})
})
},
onReady: function() {
setTimeout(function(){
that.addChatList("hello",'l');
},1000)
},
addChatList: function (word, orientation){
let ch = {'text': word,'time':new Date().getTime(), 'orientation':orientation};
chatList.push(ch);
that.setData({
chatListData: chatList
});
}
})
index.wxml
<!--index.wxml-->
<view class="container">
<block wx:for="{{chatList}}" wx:key="time">
<view class="chat-left" wx:if="{{item.orientation == 'l'}}">
<image class="avatar-img" src="../../" ></image>
<text>{{item.text}}</text>
</view>
</block>
</view>
app.json
{
"pages":[
"pages/index/index",
"pages/logs/logs"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}
app.js
//app.js
App({
onLaunch: function() {
//调用API从本地缓存中获取数据
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
},
getUserInfo: function(cb) {
var that = this
if (this.globalData.userInfo) {
typeof cb == "function" && cb(this.globalData.userInfo)
} else {
//调用登录接口
wx.getUserInfo({
withCredentials: false,
success: function(res) {
that.globalData.userInfo = res.userInfo
typeof cb == "function" && cb(that.globalData.userInfo)
}
})
}
},
globalData: {
userInfo: null
}
})
Third Step
Getting Started for WxPay
Development Items:
wx.setStorageSync 可以对本地缓存进行设置,获取和同一个微信用户,同一个小程序存储上限为10MB.localStorage以用户维度隔离,同一台设备上,A用户无法读取到B用户的数据。
wx.getStorageInfoSync 同步获取当前存储的相关信息
index.js
//index.js
//获取应用实例
var app = getApp()
var MD5Util = require('../../utils/md5.js');
Page({
data: {
motto: 'Hello World',
todos: [],
allCompleted: false,
leftCount: 0,
logs: [],
price: 0.01
},
//保存本地数据
save:function() {
//将data保存到本地指定的key中。或覆盖掉该key对应的内容,同步线程推送数据到服务器
wx.setStorageSync('todo_list', this.data.todos)
wx.setStorageSync('todo_logs', this.data.logs)
},
load:function(){
var todos = wx.getStorageInfoSync('todo_list')
if(todos){
var leftCount = todos.filter(function(item){
return !item.completed
}).length
this.setData({ todos: todos,leftCount: leftCount})
}
var logs = wx.getStorageSync('todo_logs')
if(logs){
this.setData({ logs: logs })
}
},
//事件处理函数
bindViewTap: function() {
wx.navigateTo({
url: '../logs/logs'
})
},
onLoad: function () {
this.load();
},
//输入待办事项信息
inputChangeHandle: function(e){
this.setData({
input: e.detail.value
})
},
//添加之前在this指针中保存的data变量
addTodoHandle: function(){
if(!this.data.input || !this.data.input.trim()) return
var todos = this.data.todos
todos.push({name: this.data.input,completed: false})
var logs = this.data.logs
logs.push({ timestamp: new Date(),action: 'Add',name: this.data.input })
this.setData({
input: '',
todos: todos,
leftCount: this.data.leftCount+1,
logs: logs
})
this.save()
},
//显示未完成事件
toggleTodoHandle:function(e){
var Index = e.currentTarget.dataset.index;
var todos = this.data.todos
todos[Index].completed = !todos[Index].completed
var logs = this.data.logs
logs.push({
timestamp: new Date(),
action: todos[Index].completed?'支付成功':'支付未成功',
name: todos[Index].name
})
//推送剩余未完成事件的信息
this.setData({
todos: todos,
leftCount: this.data.leftCount + (todos[Index].completed?-1:1),
logs: logs
})
this.save();
},
toggleAllHandle: function(){
//标记未完成,记录已经完成的事件数
this.data.allCompleted = !this.data.allCompleted
var todos = this.data.todos
for (var i= todos.length-1;i>=0;i--){
todos[i].completed = this.data.allCompleted
}
var logs = this.data.logs
logs.push({
timestamp: new Date(),
action: this.data.allCompleted?'支付成功':'支付未成功',
name: '全部任务'
})
this.save()
},
wxPay: function(){
var code = '' //传给服务器获得openid
var timestamp = String(Date.parse(new Date())) //时间戳
var nonceStr = ''//随机字符串,后台返回
var prepayId = '' //订单详情,预支付id,后台返回
var paySign = ''//签名算法
wx.login({
success: function(res){
if(res.code){ code =res.code //发起网络请求,发起https请求,向服务器端请求支付
wx.request({
url: 'https://www.yuluoxinsheng.cn/wxPay/JsApiPay',
data: {code: res.code},
success: function(res){
if(res.data.result == true){
//调用签名算法
nonceStr = res.data.nonceStr
prepayId = res.data.prepayId
//按照字段的首字母排序组成新的字符串
var payDataA = 'appId='+app.globalData.appId+'&nonceStr='+res.data.nonceStr+'&packeage='+prepayId+'&signType=MD5×tamp='+timestamp;
//使用MD5,key为商户注册的密钥
var payDataB =payDataA+"&key="+app.globalData.key;
paySign = MD5Util.MD5(payDataB).toUpperCase();
//发起微信支付
wx.requestPayment({
'timestamp': timestamp,
'nonceStr': nonceStr,
'packeage': 'prepayId=' + prepayId,
'signType': 'MD5',
'paySign': paySign,
'success': function(res){
//保存当前页面,跳转到某个应用内页面
wx.navigateTo({
url:'../pay/pay',
})
},
'fail':function(res){
console.log(res.errMsg);
}
})
}else{
console.log('请求失败'+res.data.info)
}
}
})
}
else{
console.log('动态请求登录失败',res.erMsg)
}
}
});
}
})