一、课程回顾
-
小程序的优势和劣势
-
小程序的开发流程
-
小程序中如何取值
-
小程序中如何进行条件渲染
-
小程序中如何进行循环渲染
-
小程序中rpx尺寸单位有什么特性
-
小程序中JS和Node中JS的区别
-
小程序的通讯模型
-
App和Page的生命周期函数有哪些
-
小程序中如何进行事件的定义,传参
二、本章任务
-
掌握小程序中常见的交互反馈设计
-
掌握微信小程序中的本地存储的使用
-
掌握在小程序中发送HTTP请求
-
掌握在小程序中封装HTTP请求
-
掌握小程序中的界面跳转
三、本章目标
-
养成良好的交互设计习惯
-
能够熟练的使用本地存储。
-
实现小程序HTTP的封装
-
实现登录状态的维护和持久化
-
掌握小程序中的界面跳转以及传参
四、知识点
1. 常见的交互反馈设计
用户和小程序上进行交互的时候,某些操作可能比较耗时,我们应该予以及时的反馈以舒缓用户等待的不良情绪。
对于一些危险操作,一定要给予提示。出现错误的时候要告诉用户错误的原因,以及如何改正。这些都是前端在开发过程需要考虑的问题,也是提现我们专业性的地方。
触摸反馈
通常页面会摆放一些button按钮或者view区域,用户触摸按钮之后会触发下一步的操作。这种情况下,我们要对触摸这个行为给予用户一些响应。
操作反馈
对于用户的操作及时响应是非常优秀的体验,有时候在点击button按钮处理更耗时的操作时,我们也会使用button组件的loading属性,在按钮的文字前边出现一个Loading,让用户明确的感觉到,这个操作会比较耗时,需要等待一小段时间。
Toast和模态对话框
在完成某个操作成功之后,我们希望告诉用户这次操作成功并且不打断用户接下来的操作。弹出式提示Toast就是用在这样的场景上,Toast提示默认1.5秒后自动消失。
toastF() {
wx.showToast({
title: '我是title',
icon: 'error',
duration: 1500
})
},
Page({
onLoad: function() {
wx.showToast({ // 显示Toast
title: '已发送',
icon: 'success',
duration: 1500
})
// wx.hideToast() // 隐藏Toast
}
})
特别要注意,对于错误信息我们不应该用Toast进行提示,因为错误提示需要明确告知用户具体原因,因此不适合用这种一闪而过的Toast弹出式提示。一般需要用户明确知晓操作结果状态的话,会使用模态对话框来提示,同时附带下一步操作的指引。
ModalF() {
wx.showModal({
// cancelColor: 'cancelColor',
title:'标题',
content: '告知当前状态,信息和解决方法',
confirmText: '主操作',
cancelText: '次要操作',
success: function(res) {
console.log(res);
if(res.confirm){
console.log('用户点击主操作')
}else if(res.cancel){
console.log('用户点击次要操作')
}
}
})
},
Page({
onLoad: function() {
wx.showModal({
title: '标题',
content: '告知当前状态,信息和解决方法',
confirmText: '主操作',
cancelText: '次要操作',
success: function(res) {
if (res.confirm) {
console.log('用户点击主操作')
} else if (res.cancel) {
console.log('用户点击次要操作')
}
}
})
}
})
课堂练习: 给Todo-list删除和发送加上提示和反馈
2. 本地存储
写入本地数据
小程序提供了读写本地数据缓存的接口,通过wx.setStorage写数据到缓存,在小程序中几乎所有接口都是异步的,这里存储数据也是一个异步操作,如果希望进行同步存储需要调用wx.setStorageSync。
异步存储
wx.setStorage({
data: {name:"天亮教育",age:4},
key: 'list',
})
同步存储
wx.setStorageSync('list1', {name:"尚云科技",age:5})
读取本地数据
在小程序中可以通过wx.getStorage/wx.getStorageSync将数据存储到本地。
异步操作
wx.getStorage({
key: 'list',
success(res){
console.log(res);
}
})
同步操作
const list = wx.getStorageSync('list')
缓存的限制和隔离
-
小程序宿主环境会管理不同小程序的数据缓存,不同小程序的本地缓存空间是分开的,每个小程序的缓存空间上限为10MB,如果当前缓存已经达到10MB,再通过wx.setStorage写入缓存会触发fail回调。
-
小程序的本地缓存不仅仅通过小程序这个维度来隔离空间,考虑到同一个设备可以登录不同微信用户,宿主环境还对不同用户的缓存进行了隔离,避免用户间的数据隐私泄露。
-
由于本地缓存是存放在当前设备,用户换设备之后无法从另一个设备读取到当前设备数据,因此用户的关键信息不建议只存在本地缓存,应该把数据放到服务器端进行持久化存储。
缓存todo-list数据
这里我们要确定什么时候把数据存到本地,什么时候把数据取出来。
存储
每次当数据发生变化的时候,我们都需要同步一份到storage中,比如增加、删除、勾选。
获取数据
每次加载到这个页面的时候,都从storage中把数据取出来,进行data数据的初始化。
课堂案例:实现todo-list数据的本地缓存
3. HTTP的使用
小程序经常需要往服务器传递数据或者从服务器拉取信息,这个时候可以使用wx.request这个API。
发送请求
接口文档:http://yapi.shangyuninfo.com/project/56/interface/api/553
以获取文章列表为例
wx.request({
url: 'https://showme.myhope365.com/api/cms/article/open/list',
method: "POST",
data: {
pageNum: 1,
pageSize: 10
},
header: {
"content-type": "application/x-www-form-urlencoded"
},
success: res => {
console.log(res.data.rows)
}
})
参数说明
-
url 开发者服务器接口地址。注意这里需要配置域名
-
data 请求的参数
-
header 设置请求的 header,header 中不能设置 Referer,默认header['content-type'] = 'application/json'
-
method(需大写)有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
-
dataType json 回包的内容格式,如果设为json,会尝试对返回的数据做一次 JSON解析
-
success 收到开发者服务成功返回的回调函数。
-
fail 接口调用失败的回调函数
-
complete 接口调用结束的回调函数(调用成功、失败都会执行)
http请求的封装
我们会发现,由于我们后台请求接口的数据格式都是表单格式的,每次发送请求会很麻烦,都需要指定请求头,另外我们这里回调函数的方式解决异步问题,写起来也可能会出现回调地域的问题。在这里我们如果想解决这些问题,就涉及到了http请求的封装。
作用:
-
添加统一的请求配置
-
可以添加请求拦截器和响应拦截器,在请求和响应之前加一些通用的处理。
封装的实现:
function request(options) {
// 请求拦截器
// ...
// 1. 加一些统一的参数,或者配置
if (!options.url.startsWith("https://") && !options.url.startsWith("http://")) {
options.url = "https://showme.myhope365.com" + options.url
}
// 默认的请求头
let header = {
"content-type": "application/x-www-form-urlencoded",
};
if (options.header) {
header = {
...header,
...options.header
}
}
return new Promise((reslove, reject) => {
// 调用接口
wx.request({
// 默认的配置
// 加载传入的配置
...options,
header,
success(res) {
// 响应拦截器,所有接口获取数据之前,都会先执行这里
// 1. 统一的错误处理
if (res.statusCode != 200) {
wx.showToast({
title: '服务器异常,请联系管理员',
})
}
reslove(res)
},
fail(err) {
reject(err)
}
})
})
}
export function get(url, options = {}) {
return request({
url,
...options
})
}
export function post(url, data, options = {}) {
return request({
url,
data,
method: "POST",
...options
})
}
课堂案例:实现文章列表功能
4. 实现登录功能
我们来基于我们的封装实现一下小程序中的登录功能。
使用第三方组件
首先搭建登录界面,在我们开发过程中一般也是会依赖一些第三方组件来加快我们开发效率。这里vant就是小程序中一个比较优秀的组件库。
官网:https://vant-contrib.gitee.io/vant-weapp/#/intro
使用步骤
-
首先这个项目需要被npm管理,所以需要先在命令行中执行npm init进行npm初始化。
-
安装vant组件库npm i @vant/weapp -S --production
-
构建npm模块
- 修改app.json
将 app.json 中的 "style": "v2" 去除,小程序的新版基础组件强行加上了许多样式,难以去除,不关闭将造成部分组件样式混乱。
搭建登录界面
按照官方文档引入表单组件,实现登录界面的还原,还原效果如下。
实现登录功能
http://yapi.shangyuninfo.com/project/56/interface/api/487
在用户填写完信息之后,点击登录按钮,调用登录接口,根据后台返回内容判断是否登录成功。
在这里,当我们输入正确的账号和密码之后,后台提示我们登录成功,但是当我们在登录成功之后在调用,获取用户信息的方法的时候,发现提示还是当前用户未登录。这是为什么呢?
这里我们后端采用的登录鉴权方式是通过cookie的方式进行的鉴权,即登录成功之后,后端会给我们cookie上增加一个JSESSIONID,这个JESSIONID就标识了当前登录用户的身份。
在浏览器中,我们每次发送请求都会携带cookie,所以说在浏览器中我们登录成功之后就可以直接调用登录之后才能访问的接口。但是在小程序端,小程序默认不会帮我们在发送请求的时候带上cookie,这个时候就需要我们手动添加请求cookie了。
在这里我们一共分为两步来实现,首先在登录成功之后,我们获取到后台返回的cookie中的JESSIONID并进行记录。
login(){
// 显示加载中效果
this.setData({
loading:true
})
login(this.data.username,this.data.password).then(res=>{
this.setData({
loading:false
})
if(res.data.code === 0 ){
const cookie = res.cookies.join(";");
// 判断包含JESSIONID之后进行持久化存储
if(cookie.includes("JSESSIONID")){
// 需要把cookie
wx.setStorageSync('cookie', cookie)
}
// 轻提示
wx.showToast({
title: '登录成功',
})
wx.switchTab({
url: '/pages/my/index',
})
}else {
// 展示模态框
wx.showModal({
title:"登录失败",
content:res.data.msg,
confirmText:"我知道了",
showCancel:false
})
}
})
},
之后,在每次发送请求的时候,在请求同中添加上cookie属性。这里由于我们进行了封装,所以每次发送请求都会执行我们封装好的request方法,我们可以在这里给所有的接口加上cookie
function request(options) {
// 请求拦截器
// ...
// 1. 加一些统一的参数,或者配置
if (!options.url.startsWith("https://") && !options.url.startsWith("http://")) {
options.url = "https://showme.myhope365.com" + options.url
}
// 默认的请求头
let header = {
"content-type": "application/x-www-form-urlencoded",
// 加上统一的cookie
"cookie": wx.getStorageSync("cookie") || ""
};
if (options.header) {
header = {
...header,
...options.header
}
}
return new Promise((reslove, reject) => {
// 调用接口
wx.request({
// 默认的配置
// 加载传入的配置
...options,
header,
success(res) {
// 响应拦截器,所有接口获取数据之前,都会先执行这里
// 1. 统一的错误处理
if (res.statusCode != 200) {
wx.showToast({
title: '服务器异常,请联系管理员',
})
}
reslove(res)
},
fail(err) {
reject(err)
}
})
})
}
记住登录状态
现在我们已经实现了登录功能,但是这里的cookie是有可能会过期的,并且对于未登录的用户,我们应该一上来显示登录界面,对于已经登录的用户一上来可能需要显示用户信息界面,所以这里就涉及到了用户登录状态的记录。
我们可以通过调用获取用户详情的接口来判断当前登录状态是否过期。我们可以在App的生命周期函数中进行调用这个接口,检查一下登录状态。
因为这里接口调用是异步调用,所以需要通过promise解决异步问题。通过App实例可以记录当前登录状态供别的地方使用。
this.globalData.loginPromise = getUserInfo().then(res=>{
if(res.data.code === 0){
console.log("登录.....");
// 登录状态
this.globalData.isLogin = true;
this.globalData.user = res.data.data
}else {
// 未登录
console.log("未登录.....");
this.globalData.isLogin = false;
this.globalData.user = null
}
})
小程序的界面跳转
navigateTo
一个小程序拥有多个页面,我们可以通过wx.navigateTo推入一个新的页面。
wx.navigateTo({
url: '/pages/user/index',
})
switchTab
当我们跳转的页面是tabbar界面的时候必须要使用switchTab的方式进行跳转。
navigateBack
通过navigateBack可以退回到上一个界面。
reLaunch
清空页面栈跳转到指定界面。
redirectTo
界面重定向,先关闭当前页面,在跳转到指定界面
路由跳转传参
路由跳转传参可以通过?的方式拼接参数。跳转到指定界面之后,可以在该页面的onLoad方法中的options参数拿到路由跳转的参数。
五、总结
见第一天总结
六、作业
1. 完成登录功能。
2. 完成首页信息的展示,包括新闻轮播图和新闻列表。
3. 完成个人中心界面的渲染。