小程序常見的應用場景
一、課程回顧
-
小程序的優勢和劣勢
-
小程序的開發流程
-
小程序中如何取值
-
小程序中如何進行條件渲染
-
小程序中如何進行循環渲染
-
小程序中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. 完成個人中心界面的渲染。