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

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

微信小程序 - 微信打赏Step by Step_第1张图片
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



  

    
      
      {{item.text}}
    
  

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:

  • 微信Oauth2授权验证
微信小程序 - 微信打赏Step by Step_第2张图片
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×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)
        }
      }
    });

  }

})

你可能感兴趣的:(微信小程序 - 微信打赏Step by Step)