界面常见的交互反馈
查看更多学习笔记:GitHub:LoveEmiliaForever
微信小程序开发指南
微信小程序开发文档
用户和小程序上进行交互的时候,某些操作可能比较耗时,我们应该予以及时的反馈以舒缓用户等待的不良情绪(良好的使用体验)
触摸反馈
通常页面会摆放一些button按钮或者view区域,用户触摸按钮之后会触发下一步的操作,这种情况下,我们要对触摸这个行为给予用户一些响应
小程序的view容器组件和button组件提供了hover-class
属性,触摸时会往该组件加上对应的class
改变组件的样式
.hover{
background-color: gray;
}
<button hover-class="hover"> 点击button </button>
<view hover-class="hover"> 点击view</view>
有时候在点击button按钮处理更耗时的操作时,我们也会使用button组件的loading
属性,在按钮的文字前边出现一个Loading(一直转的圈圈)
<button loading="{{loading}}" bindtap="tap">操作</button>
Page({
data: { loading: false },
tap: function() {
// 把按钮的loading状态显示出来
this.setData({
loading: true
})
// 接着做耗时的操作
}
})
Toast和模态对话框
弹出式提示Toast
用在显示提示消息的场景上,Toast提示默认1.5秒后自动消失
Page({
onLoad: function() {
wx.showToast({ // 显示Toast
title: '已发送',
icon: 'success',
duration: 1500
})
// wx.hideToast() // 隐藏Toast
}
})
一般需要正式的提示框的话,会使用模态对话框
来提示,同时附带下一步操作的指引
Page({
onLoad: function() {
wx.showModal({
title: '标题',
content: '告知当前状态,信息和解决方法',
confirmText: '主操作',
cancelText: '次要操作',
success: function(res) {
if (res.confirm) {
console.log('用户点击主操作')
} else if (res.cancel) {
console.log('用户点击次要操作')
}
}
})
}
})
界面滚动
为了让用户可以快速刷新当前界面的信息,一般在小程序里会通过下拉整个界面这个操作来触发(下拉刷新)
宿主环境提供了统一的下拉刷新交互,开发者只需要通过配置开启当前页面的下拉刷新
用户往下拉动界面触发下拉刷新操作时,Page构造器
的onPullDownRefresh
回调会被触发,此时开发者重新拉取新数据进行渲染
//page.json
{"enablePullDownRefresh": true }
//page.js
Page({
onPullDownRefresh: function() {
// 用户触发了下拉刷新操作
// 拉取新数据重新渲染界面
// wx.stopPullDownRefresh() // 可以停止当前页面的下拉刷新。
}
})
有时当滚动到底部时,会再加载一些数据渲染出来
这个交互操作叫为上拉触底
,宿主环境提供了上拉的配置和操作触发的回调
//page.json
// 界面的下方距离页面底部距离小于onReachBottomDistance像素时触发onReachBottom回调
{"onReachBottomDistance": 100 }
//page.js
Page({
onReachBottom: function() {
// 当界面的下方距离页面底部距离小于100像素时触发回调
}
})
当然我们有些时候并不想整个页面进行滚动,而是页面中某一小块区域需要可滚动,此时就要用到宿主环境所提供的scroll-view
可滚动视图组件
可以通过组件的scroll-x
和scroll-y
属性决定滚动区域是否可以横向或者纵向滚动,scroll-view组件也提供了丰富的滚动回调触发事件
发起HTTPS网络通信
小程序经常需要往服务器传递数据或者从服务器拉取信息,这个时候可以使用wx.request
这个API
wx.request({
url: 'https://test.com/getinfo',
success: function(res) {
console.log(res)// 服务器回包信息
}
})
服务器接口
url参数是当前发起请求的服务器接口地址,小程序宿主环境要求request发起的网络请求必须是https
协议请求,因此开发者服务器必须提供HTTPS服务的接口
wx.request请求的域名需要在小程序管理平台进行配置
请求参数
通过wx.request这个API,有两种方法把数据传递到服务器:通过url上的参数
以及通过data参数
url:'https://test.com/getinfo?id=1&version=1.0.0'
或者是data: { id:1, version:'1.0.0' }
header参数设置content-type头部为application/json,小程序发起的请求的包体内容就是data参数对应的JSON字符串
收到回包
小程序端收到回包后会触发success回调,同时回调会带上一个Object信息(属性如下)
只要成功收到服务器返回,无论HTTP状态码是多少都会进入success回调
使用技巧
设置超时时间
默认的request超时时间是60秒,可以通过app.json指定超时时间大小
{
"networkTimeout": {"request": 3000}
}
微信登录
获取微信登录凭证code
上述微信登录的流程中并不是通过wx.login直接获取微信用户的id
如果以id为信息直接发送请求获取数据,那么可以通过伪造请求获取服务器的信息
wx.login生成一个带有时效性的凭证称为微信登录凭证code
,其有效时间仅为5分钟
发送code到开发者服务器
在wx.login的success回调中拿到微信登录凭证,紧接着会通过wx.request把code传到开发者服务器,为了后续可以换取微信用户身份id
Page({
tapLogin: function() {
wx.login({
success: function(res) {
if (res.code) {
wx.request({
url: 'https://test.com/login',
data: {
username: 'zhangsan', // 用户输入的账号
password: 'pwd123456', // 用户输入的密码
code: res.code
},
success: function(res) {
// 登录成功
if (res.statusCode === 200) {
console.log(res.data.sessionId)// 服务器回包内容
}
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
});
}
})
到微信服务器换取微信用户身份id
后台拿到了前边wx.login()所生成的微信登录凭证code,此时就可以拿这个code到微信服务器换取微信用户身份
微信服务器为了确保拿code过来换取身份信息的人就是刚刚对应的小程序开发者,到微信服务器的请求要同时带上AppId
和AppSecret
AppId和AppSecret是微信鉴别开发者身份的重要信息,AppId是公开信息,但是AppSecret是开发者的隐私数据不应该泄露
code在成功换取一次信息之后会立即失效
微信服务器提供的接口地址是:
https://api.weixin.qq.com/sns/jscode2session?appid=<AppId>&secret=<AppSecret>&js_code=<code>&grant_type=authorization_code
接口会返回以下字段:
- openid就是前文一直提到的微信用户id,可以用这个id来区分不同的微信用户
- 开发者可以用session_key请求微信服务器其他接口来获取一些其他信息(不要泄露)
绑定微信用户身份id和业务用户身份
微信会建议开发者把这两个信息的对应关系存起来,我们把这个对应关系称之为“绑定”
有了这个绑定信息,小程序在下次需要用户登录的时候就可以不需要输入账号密码
这样静默授权的登录方式显得非常便捷
业务登录凭证SessionId
开发者服务器和开发者的小程序应该也有会话密钥,在本书中我们就把它称之为SessionId
用户登录成功之后,开发者服务器需要生成会话密钥SessionId,在服务端保持SessionId对应的用户身份信息,同时把SessionId返回给小程序
小程序后续发起的请求中携带上SessionId,开发者服务器就可以通过服务器端的Session信息查询到当前登录用户的身份
这样我们就不需要每次都重新获取code,省去了很多通信消耗
本地数据缓存
本地数据缓存是小程序存储在当前设备上硬盘上的数据
我们可以利用本地数据缓存来存储用户在小程序上产生的操作
我们还可以利用本地缓存一些服务端非实时的数据提高小程序获取数据的速度
读写本地数据缓存
- 通过
wx.getStorage
/wx.getStorageSync
读取本地缓存 - 通过
wx.setStorage
/wx.setStorageSync
写数据到缓存 - Sync后缀的接口表示是同步接口
wx.getStorage的使用
wx.getStorage({
key: 'key1',
success: function(res) {
// 异步接口在success回调才能拿到返回值
var value1 = res.data
},
fail: function() {
console.log('读取key1发生错误')
}
})
wx.setStorage的使用
wx.setStorage({
key:"key",
data:"value1"
success: function() {
console.log('写入value1成功')
},
fail: function() {
console.log('写入value1发生错误')
}
})
缓存限制和隔离
小程序宿主环境会管理不同小程序的数据缓存,不同小程序的本地缓存空间是分开的,每个小程序的缓存空间上限为10MB
考虑到同一个设备可以登录不同微信用户,宿主环境还对不同用户的缓存进行了隔离,避免用户间的数据隐私泄露
用户的关键信息不建议只存在本地缓存,应该把数据放到服务器端进行持久化存储
利用本地缓存提前渲染界面
- 我们在拉取信息数据后把数据存在本地缓存里
- 在onLoad发起请求前,先检查是否有缓存过数据
- 如果有的话直接渲染用户界面
- 然后等到wx.request的success回调之后再覆盖本地缓存重新渲染新的用户界面
一般在对数据实时性/一致性要求不高的页面采用这个方法来做提前渲染,用以优化小程序体验
缓存用户登录态SessionId
通常用户在没有主动退出登录前,用户的登录态会一直保持一段时间,就无需用户频繁地输入账号密码
如果我们把SessionId记录在Javascript中某个内存变量,当用户关闭小程序再进来小程序时,之前内存的SessionId已经丢失,此时我们就需要利用本地缓存的能力来持久化存储SessionId
//page.js
var app = getApp()
Page({
onLoad: function() {
// 调用wx.login获取微信登录凭证
wx.login({
success: function(res) {
// 拿到微信登录凭证之后去自己服务器换取自己的登录凭证
wx.request({
url: 'https://test.com/login',
data: { code: res.code },
success: function(res) {
var data = res.data
// 把 SessionId 和过期时间放在内存中的全局对象和本地缓存里边
app.globalData.sessionId =data.sessionId
wx.setStorageSync('SESSIONID',data.sessionId)
// 假设登录态保持1天
var expiredTime = +new Date() +1*24*60*60*1000
app.globalData.expiredTime =expiredTime
wx.setStorageSync('EXPIREDTIME',expiredTime)
}
})
}
})
}
})
在重新打开小程序的时候,我们把上一次存储的SessionId内容取出来,恢复到内存
//app.js
App({
onLaunch: function(options) {
var sessionId =wx.getStorageSync('SESSIONID')
var expiredTime =wx.getStorageSync('EXPIREDTIME')
var now = +new Date()
if (now - expiredTime <=1*24*60*60*1000) {
this.globalData.sessionId = sessionId
this.globalData.expiredTime = expiredTime
}
},
globalData: {
sessionId: null,
expiredTime: 0
}
})
设备能力
小程序的宿主环境提供了非常多的操作设备能力来帮助用户在特定场景下做高效的输入,例如:扫码
、操控蓝牙
等等能力
也有很多设备能力不是为了解决输入低效问题而设计的,它们更多的是解决用户侧一些体验问题,例如:获取设备网络状态
、调整屏幕亮度
等等
利用微信扫码能力
- 把复杂的信息编码成一个二维码
- 利用宿主环境
wx.scanCode
这个API调起微信扫一扫 - 扫码后,wx.scanCode的success回调会收到二维码对应的字符串信息
//page.js
Page({
// 点击“扫码订餐”的按钮,触发tapScan回调
tapScan: function() {
// 调用wx.login获取微信登录凭证
wx.scanCode({
success: function(res) {
var num = res.result // 获取到的num就是餐桌的编号
}
})
}
})
获取网络状态
手机连接到互联网有几种方式:Wifi、2G、3G、4G、5G
每种方式的上传速度和下载速度差异很大,它们的计费方式的差异也很大
考虑到这样的情况,我们可以通过小程序提供的获取网络状态的能力,做一些更友好的体验提示
利用wx.getNetworkType
获取网络状态
//page.js
Page({
// 点击“预览文档”的按钮,触发tap回调
tap: function() {
wx.getNetworkType({
success: function(res) {
// networkType字段的有效值:
// wifi/2g/3g/4g/unknown(Android下不常见的网络类型)/none(无网络)
if (res.networkType == 'wifi') {
// 从网络上下载pdf文档
wx.downloadFile({
url:'http://test.com/somefile.pdf',
success: function (res) {
// 下载成功之后进行预览文档
wx.openDocument({
filePath: res.tempFilePath
})
}
})
} else {
wx.showToast({ title: '当前为非Wifi环境' })
}
}
})
}
})
小程序宿主环境也提供了一个可以动态监听网络状态变化的接口wx.onNetworkStatusChange
,让开发者可以及时根据网络状况去调整小程序的体验