微信小程序 - 微信打赏Step by Step

应一位小程序开发者的需求,对微信打赏接口进行测试。本人接触微信小程序的时间不长,解析微信事项打赏
项目结构目录树

Project.jpg

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绑定数组为dataJson中的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:

wxOauth2.jpg
  • 微信支付参数列表

  • 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&timestamp='+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)
        }
      }
    });

  }

})
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容